diff options
Diffstat (limited to 'chromium/v8')
182 files changed, 6760 insertions, 7121 deletions
diff --git a/chromium/v8/ChangeLog b/chromium/v8/ChangeLog index d824cec0d63..b0ab892073e 100644 --- a/chromium/v8/ChangeLog +++ b/chromium/v8/ChangeLog @@ -1,60 +1,3 @@ -2013-08-14: Version 3.20.17 - - Fixed Math.round/floor that had bogus Smi representation - (Chromium issue 272564) - - Performance and stability improvements on all platforms. - - -2013-08-13: Version 3.20.16 - - Fixed bug in HPhi::SimplifyConstantInput (Chromium issue 269679) - - Fixed gcmole bugs in i18n code (issue 2745) - - ia32: Calls to the TranscendentalCacheStub must ensure that esi is - set (issue 2827) - - Made sure polymorphic element access creates non-replaying - phis. (issue 2815) - - Allowed HPhis to have an invalid merge index. (issue 2815) - - Fixed smi-based math floor. (Chromium issue 270268) - - Deprecated self and total time getters and total sample count - getter on CpuProfileNode. (Chromium issue 267595) - - Fixed Object.freeze, Object.observe wrt CountOperation and - CompoundAssignment. (issue 2774,2779) - - Performance and stability improvements on all platforms. - - -2013-08-07: Version 3.20.14 - - Exposed eternal handle api. - - Bugfix to solve issues with enabling V8 typed arrays in Blink. - - Fixed Array index dehoisting. (Chromium issue 264203) - - Updated Array Iterator to use numeric indexes (issue 2818) - - Return start/end profiling time in microseconds instead of milliseconds - (issue 2824) - - Performance and stability improvements on all platforms. - - -2013-08-06: Version 3.20.14 - - Added new Harmony methods to Array.prototype object. - (issue 2776,v8:2777) - - Performance and stability improvements on all platforms. - - 2013-08-01: Version 3.20.12 Removed buggy ToNumber truncation (partial fix for issue 2813) diff --git a/chromium/v8/Makefile b/chromium/v8/Makefile index 288c257396d..499f6cb08e0 100644 --- a/chromium/v8/Makefile +++ b/chromium/v8/Makefile @@ -192,7 +192,6 @@ endif # ----------------- available targets: -------------------- # - "dependencies": pulls in external dependencies (currently: GYP) -# - "grokdump": rebuilds heap constants lists used by grokdump # - any arch listed in ARCHES (see below) # - any mode listed in MODES # - every combination <arch>.<mode>, e.g. "ia32.release" @@ -393,7 +392,7 @@ endif # Replaces the old with the new environment file if they're different, which # will trigger GYP to regenerate Makefiles. $(ENVFILE): $(ENVFILE).new - @if test -r $(ENVFILE) && cmp $(ENVFILE).new $(ENVFILE) > /dev/null; \ + @if test -r $(ENVFILE) && cmp $(ENVFILE).new $(ENVFILE) >/dev/null; \ then rm $(ENVFILE).new; \ else mv $(ENVFILE).new $(ENVFILE); fi @@ -402,12 +401,6 @@ $(ENVFILE).new: @mkdir -p $(OUTDIR); echo "GYPFLAGS=$(GYPFLAGS)" > $(ENVFILE).new; \ echo "CXX=$(CXX)" >> $(ENVFILE).new -# Heap constants for grokdump. -DUMP_FILE = tools/v8heapconst.py -grokdump: ia32.release - @cat $(DUMP_FILE).tmpl > $(DUMP_FILE) - @$(OUTDIR)/ia32.release/d8 --dump-heap-constants >> $(DUMP_FILE) - # Dependencies. # Remember to keep these in sync with the DEPS file. dependencies: diff --git a/chromium/v8/include/v8-debug.h b/chromium/v8/include/v8-debug.h index bacccb61ddf..e488aaa8891 100755 --- a/chromium/v8/include/v8-debug.h +++ b/chromium/v8/include/v8-debug.h @@ -30,6 +30,40 @@ #include "v8.h" +#ifdef _WIN32 +typedef int int32_t; +typedef unsigned int uint32_t; +typedef unsigned short uint16_t; // NOLINT +typedef long long int64_t; // NOLINT + +// Setup for Windows DLL export/import. See v8.h in this directory for +// information on how to build/use V8 as a DLL. +#if defined(BUILDING_V8_SHARED) && defined(USING_V8_SHARED) +#error both BUILDING_V8_SHARED and USING_V8_SHARED are set - please check the\ + build configuration to ensure that at most one of these is set +#endif + +#ifdef BUILDING_V8_SHARED +#define EXPORT __declspec(dllexport) +#elif USING_V8_SHARED +#define EXPORT __declspec(dllimport) +#else +#define EXPORT +#endif + +#else // _WIN32 + +// Setup for Linux shared library export. See v8.h in this directory for +// information on how to build/use V8 as shared library. +#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(V8_SHARED) +#define EXPORT __attribute__ ((visibility("default"))) +#else // defined(__GNUC__) && (__GNUC__ >= 4) +#define EXPORT +#endif // defined(__GNUC__) && (__GNUC__ >= 4) + +#endif // _WIN32 + + /** * Debugger support for the V8 JavaScript engine. */ @@ -47,7 +81,7 @@ enum DebugEvent { }; -class V8_EXPORT Debug { +class EXPORT Debug { public: /** * A client object passed to the v8 debugger whose ownership will be taken by diff --git a/chromium/v8/include/v8-preparser.h b/chromium/v8/include/v8-preparser.h index 1da77185af8..3e39823d65c 100644 --- a/chromium/v8/include/v8-preparser.h +++ b/chromium/v8/include/v8-preparser.h @@ -28,14 +28,48 @@ #ifndef PREPARSER_H #define PREPARSER_H -#include "v8.h" #include "v8stdint.h" +#ifdef _WIN32 + +// 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 +// the V8 DLL USING_V8_SHARED needs to be defined. When either building the V8 +// static library or building a program which uses the V8 static library neither +// BUILDING_V8_SHARED nor USING_V8_SHARED should be defined. +#if defined(BUILDING_V8_SHARED) && defined(USING_V8_SHARED) +#error both BUILDING_V8_SHARED and USING_V8_SHARED are set - please check the\ + build configuration to ensure that at most one of these is set +#endif + +#ifdef BUILDING_V8_SHARED +#define V8EXPORT __declspec(dllexport) +#elif USING_V8_SHARED +#define V8EXPORT __declspec(dllimport) +#else +#define V8EXPORT +#endif // BUILDING_V8_SHARED + +#else // _WIN32 + +// Setup for Linux shared library export. There is no need to distinguish +// between building or using the V8 shared library, but we should not +// export symbols when we are building a static library. +#if defined(__GNUC__) && ((__GNUC__ >= 4) || \ + (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(V8_SHARED) +#define V8EXPORT __attribute__ ((visibility("default"))) +#else +#define V8EXPORT +#endif + +#endif // _WIN32 + + namespace v8 { // The result of preparsing is either a stack overflow error, or an opaque // blob of data that can be passed back into the parser. -class V8_EXPORT PreParserData { +class V8EXPORT PreParserData { public: PreParserData(size_t size, const uint8_t* data) : data_(data), size_(size) { } @@ -60,7 +94,7 @@ class V8_EXPORT PreParserData { // Interface for a stream of Unicode characters. -class V8_EXPORT UnicodeInputStream { // NOLINT - V8_EXPORT is not a class name. +class V8EXPORT UnicodeInputStream { // NOLINT - Thinks V8EXPORT is class name. public: virtual ~UnicodeInputStream(); @@ -76,9 +110,11 @@ class V8_EXPORT UnicodeInputStream { // NOLINT - V8_EXPORT is not a class name. // more stack space than the limit provided, the result's stack_overflow() // method will return true. Otherwise the result contains preparser // data that can be used by the V8 parser to speed up parsing. -PreParserData V8_EXPORT Preparse(UnicodeInputStream* input, +PreParserData V8EXPORT Preparse(UnicodeInputStream* input, size_t max_stack_size); } // namespace v8. +#undef V8EXPORT + #endif // PREPARSER_H diff --git a/chromium/v8/include/v8-profiler.h b/chromium/v8/include/v8-profiler.h index e538f4a8406..7898fef1967 100644 --- a/chromium/v8/include/v8-profiler.h +++ b/chromium/v8/include/v8-profiler.h @@ -30,6 +30,36 @@ #include "v8.h" +#ifdef _WIN32 +// Setup for Windows DLL export/import. See v8.h in this directory for +// information on how to build/use V8 as a DLL. +#if defined(BUILDING_V8_SHARED) && defined(USING_V8_SHARED) +#error both BUILDING_V8_SHARED and USING_V8_SHARED are set - please check the\ + build configuration to ensure that at most one of these is set +#endif + +#ifdef BUILDING_V8_SHARED +#define V8EXPORT __declspec(dllexport) +#elif USING_V8_SHARED +#define V8EXPORT __declspec(dllimport) +#else +#define V8EXPORT +#endif + +#else // _WIN32 + +// Setup for Linux shared library export. See v8.h in this directory for +// information on how to build/use V8 as shared library. +#if defined(__GNUC__) && ((__GNUC__ >= 4) || \ + (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(V8_SHARED) +#define V8EXPORT __attribute__ ((visibility("default"))) +#else +#define V8EXPORT +#endif + +#endif // _WIN32 + + /** * Profiler support for the V8 JavaScript engine. */ @@ -40,7 +70,7 @@ typedef uint32_t SnapshotObjectId; /** * CpuProfileNode represents a node in a call graph. */ -class V8_EXPORT CpuProfileNode { +class V8EXPORT CpuProfileNode { public: /** Returns function name (empty string for anonymous functions.) */ Handle<String> GetFunctionName() const; @@ -61,27 +91,20 @@ class V8_EXPORT CpuProfileNode { * Returns total (self + children) execution time of the function, * in milliseconds, estimated by samples count. */ - V8_DEPRECATED(double GetTotalTime() const); + double GetTotalTime() const; /** * Returns self execution time of the function, in milliseconds, * estimated by samples count. */ - V8_DEPRECATED(double GetSelfTime() const); + double GetSelfTime() const; /** Returns the count of samples where function exists. */ - V8_DEPRECATED(double GetTotalSamplesCount() const); + double GetTotalSamplesCount() const; - /** DEPRECATED. Please use GetHitCount instead. - * Returns the count of samples where function was currently executing. - */ + /** Returns the count of samples where function was currently executing. */ double GetSelfSamplesCount() const; - /** - * Returns the count of samples where the function was currently executing. - */ - unsigned GetHitCount() const; - /** Returns function entry UID. */ unsigned GetCallUid() const; @@ -102,7 +125,7 @@ class V8_EXPORT CpuProfileNode { * CpuProfile contains a CPU profile in a form of top-down call tree * (from main() down to functions that do all the work). */ -class V8_EXPORT CpuProfile { +class V8EXPORT CpuProfile { public: /** Returns CPU profile UID (assigned by the profiler.) */ unsigned GetUid() const; @@ -153,7 +176,7 @@ class V8_EXPORT CpuProfile { * Interface for controlling CPU profiling. Instance of the * profiler can be retrieved using v8::Isolate::GetCpuProfiler. */ -class V8_EXPORT CpuProfiler { +class V8EXPORT CpuProfiler { public: /** * A note on security tokens usage. As scripts from different @@ -199,11 +222,6 @@ class V8_EXPORT CpuProfiler { */ void DeleteAllCpuProfiles(); - /** - * Tells the profiler whether the embedder is idle. - */ - void SetIdle(bool is_idle); - private: CpuProfiler(); ~CpuProfiler(); @@ -219,7 +237,7 @@ class HeapGraphNode; * HeapSnapshotEdge represents a directed connection between heap * graph nodes: from retainers to retained nodes. */ -class V8_EXPORT HeapGraphEdge { +class V8EXPORT HeapGraphEdge { public: enum Type { kContextVariable = 0, // A variable from a function context. @@ -255,7 +273,7 @@ class V8_EXPORT HeapGraphEdge { /** * HeapGraphNode represents a node in a heap graph. */ -class V8_EXPORT HeapGraphNode { +class V8EXPORT HeapGraphNode { public: enum Type { kHidden = 0, // Hidden node, may be filtered when shown to user. @@ -307,7 +325,7 @@ class V8_EXPORT HeapGraphNode { /** * HeapSnapshots record the state of the JS heap at some moment. */ -class V8_EXPORT HeapSnapshot { +class V8EXPORT HeapSnapshot { public: enum SerializationFormat { kJSON = 0 // See format description near 'Serialize' method. @@ -377,7 +395,7 @@ class RetainedObjectInfo; * Interface for controlling heap profiling. Instance of the * profiler can be retrieved using v8::Isolate::GetHeapProfiler. */ -class V8_EXPORT HeapProfiler { +class V8EXPORT HeapProfiler { public: /** * Callback function invoked for obtaining RetainedObjectInfo for @@ -515,7 +533,7 @@ class V8_EXPORT HeapProfiler { * keeps them alive only during snapshot collection. Afterwards, they * are freed by calling the Dispose class function. */ -class V8_EXPORT RetainedObjectInfo { // NOLINT +class V8EXPORT RetainedObjectInfo { // NOLINT public: /** Called by V8 when it no longer needs an instance. */ virtual void Dispose() = 0; @@ -581,4 +599,7 @@ struct HeapStatsUpdate { } // namespace v8 +#undef V8EXPORT + + #endif // V8_V8_PROFILER_H_ diff --git a/chromium/v8/include/v8-testing.h b/chromium/v8/include/v8-testing.h index 97b467a91b1..59eebf9db47 100644 --- a/chromium/v8/include/v8-testing.h +++ b/chromium/v8/include/v8-testing.h @@ -30,12 +30,42 @@ #include "v8.h" +#ifdef _WIN32 +// Setup for Windows DLL export/import. See v8.h in this directory for +// information on how to build/use V8 as a DLL. +#if defined(BUILDING_V8_SHARED) && defined(USING_V8_SHARED) +#error both BUILDING_V8_SHARED and USING_V8_SHARED are set - please check the\ + build configuration to ensure that at most one of these is set +#endif + +#ifdef BUILDING_V8_SHARED +#define V8EXPORT __declspec(dllexport) +#elif USING_V8_SHARED +#define V8EXPORT __declspec(dllimport) +#else +#define V8EXPORT +#endif + +#else // _WIN32 + +// Setup for Linux shared library export. See v8.h in this directory for +// information on how to build/use V8 as shared library. +#if defined(__GNUC__) && ((__GNUC__ >= 4) || \ + (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(V8_SHARED) +#define V8EXPORT __attribute__ ((visibility("default"))) +#else +#define V8EXPORT +#endif + +#endif // _WIN32 + + /** * Testing support for the V8 JavaScript engine. */ namespace v8 { -class V8_EXPORT Testing { +class V8EXPORT Testing { public: enum StressType { kStressTypeOpt, @@ -69,7 +99,7 @@ class V8_EXPORT Testing { } // namespace v8 -#undef V8_EXPORT +#undef V8EXPORT #endif // V8_V8_TEST_H_ diff --git a/chromium/v8/include/v8.h b/chromium/v8/include/v8.h index 3252602bcf1..3eb4794f5c6 100644 --- a/chromium/v8/include/v8.h +++ b/chromium/v8/include/v8.h @@ -40,9 +40,6 @@ #include "v8stdint.h" -// We reserve the V8_* prefix for macros defined in V8 public API and -// assume there are no name conflicts with the embedder's code. - #ifdef _WIN32 // Setup for Windows DLL export/import. When building the V8 DLL the @@ -56,11 +53,11 @@ #endif #ifdef BUILDING_V8_SHARED -#define V8_EXPORT __declspec(dllexport) +#define V8EXPORT __declspec(dllexport) #elif USING_V8_SHARED -#define V8_EXPORT __declspec(dllimport) +#define V8EXPORT __declspec(dllimport) #else -#define V8_EXPORT +#define V8EXPORT #endif // BUILDING_V8_SHARED #else // _WIN32 @@ -69,12 +66,12 @@ #if defined(__GNUC__) && ((__GNUC__ >= 4) || \ (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(V8_SHARED) #ifdef BUILDING_V8_SHARED -#define V8_EXPORT __attribute__ ((visibility("default"))) +#define V8EXPORT __attribute__ ((visibility("default"))) #else -#define V8_EXPORT +#define V8EXPORT #endif #else -#define V8_EXPORT +#define V8EXPORT #endif #endif // _WIN32 @@ -388,11 +385,6 @@ template <class T> class Handle { }; -// A value which will never be returned by Local::Eternalize -// Useful for static initialization -const int kUninitializedEternalIndex = -1; - - /** * A light-weight stack-allocated object handle. All operations * that return objects from within v8 return them in local handles. They @@ -438,11 +430,6 @@ template <class T> class Local : public Handle<T> { return Local<S>::Cast(*this); } - // Keep this Local alive for the lifetime of the Isolate. - // It remains retrievable via the returned index, - V8_INLINE(int Eternalize(Isolate* isolate)); - V8_INLINE(static Local<T> GetEternal(Isolate* isolate, int index)); - /** * Create a local handle for the content of another handle. * The referee is kept alive by the local handle even when @@ -814,7 +801,7 @@ template <class T> class Persistent // NOLINT * handle and may deallocate it. The behavior of accessing a handle * for which the handle scope has been deleted is undefined. */ -class V8_EXPORT HandleScope { +class V8EXPORT HandleScope { public: // TODO(svenpanne) Deprecate me when Chrome is fixed! HandleScope(); @@ -853,7 +840,7 @@ class V8_EXPORT HandleScope { // This Data class is accessible internally as HandleScopeData through a // typedef in the ImplementationUtilities class. - class V8_EXPORT Data { + class V8EXPORT Data { public: internal::Object** next; internal::Object** limit; @@ -886,7 +873,7 @@ class V8_EXPORT HandleScope { /** * The superclass of values and API object templates. */ -class V8_EXPORT Data { +class V8EXPORT Data { private: Data(); }; @@ -898,7 +885,7 @@ class V8_EXPORT Data { * compiling it, and can be stored between compilations. When script * data is given to the compile method compilation will be faster. */ -class V8_EXPORT ScriptData { // NOLINT +class V8EXPORT ScriptData { // NOLINT public: virtual ~ScriptData() { } @@ -976,7 +963,7 @@ class ScriptOrigin { /** * A compiled JavaScript script. */ -class V8_EXPORT Script { +class V8EXPORT Script { public: /** * Compiles the specified script (context-independent). @@ -1094,7 +1081,7 @@ class V8_EXPORT Script { /** * An error message. */ -class V8_EXPORT Message { +class V8EXPORT Message { public: Local<String> Get() const; Local<String> GetSourceLine() const; @@ -1166,7 +1153,7 @@ class V8_EXPORT Message { * snapshot of the execution stack and the information remains valid after * execution continues. */ -class V8_EXPORT StackTrace { +class V8EXPORT StackTrace { public: /** * Flags that determine what information is placed captured for each @@ -1215,7 +1202,7 @@ class V8_EXPORT StackTrace { /** * A single JavaScript stack frame. */ -class V8_EXPORT StackFrame { +class V8EXPORT StackFrame { public: /** * Returns the number, 1-based, of the line for the associate function call. @@ -1267,29 +1254,13 @@ class V8_EXPORT StackFrame { }; -/** - * A JSON Parser. - */ -class V8_EXPORT JSON { - public: - /** - * Tries to parse the string |json_string| and returns it as value if - * successful. - * - * \param json_string The string to parse. - * \return The corresponding value if successfully parsed. - */ - static Local<Value> Parse(Local<String> json_string); -}; - - // --- Value --- /** * The superclass of all JavaScript values and objects. */ -class V8_EXPORT Value : public Data { +class V8EXPORT Value : public Data { public: /** * Returns true if this value is the undefined value. See ECMA-262 @@ -1520,14 +1491,14 @@ class V8_EXPORT Value : public Data { /** * The superclass of primitive values. See ECMA-262 4.3.2. */ -class V8_EXPORT Primitive : public Value { }; +class V8EXPORT Primitive : public Value { }; /** * A primitive boolean value (ECMA-262, 4.3.14). Either the true * or false value. */ -class V8_EXPORT Boolean : public Primitive { +class V8EXPORT Boolean : public Primitive { public: bool Value() const; V8_INLINE(static Handle<Boolean> New(bool value)); @@ -1537,7 +1508,7 @@ class V8_EXPORT Boolean : public Primitive { /** * A JavaScript string value (ECMA-262, 4.3.17). */ -class V8_EXPORT String : public Primitive { +class V8EXPORT String : public Primitive { public: enum Encoding { UNKNOWN_ENCODING = 0x1, @@ -1643,7 +1614,7 @@ class V8_EXPORT String : public Primitive { */ bool IsExternalAscii() const; - class V8_EXPORT ExternalStringResourceBase { // NOLINT + class V8EXPORT ExternalStringResourceBase { // NOLINT public: virtual ~ExternalStringResourceBase() {} @@ -1672,7 +1643,7 @@ class V8_EXPORT String : public Primitive { * ExternalStringResource to manage the life cycle of the underlying * buffer. Note that the string data must be immutable. */ - class V8_EXPORT ExternalStringResource + class V8EXPORT ExternalStringResource : public ExternalStringResourceBase { public: /** @@ -1706,7 +1677,7 @@ class V8_EXPORT String : public Primitive { * Use String::New or convert to 16 bit data for non-ASCII. */ - class V8_EXPORT ExternalAsciiStringResource + class V8EXPORT ExternalAsciiStringResource : public ExternalStringResourceBase { public: /** @@ -1859,7 +1830,7 @@ class V8_EXPORT String : public Primitive { * then the length() method returns 0 and the * operator returns * NULL. */ - class V8_EXPORT Utf8Value { + class V8EXPORT Utf8Value { public: explicit Utf8Value(Handle<v8::Value> obj); ~Utf8Value(); @@ -1882,7 +1853,7 @@ class V8_EXPORT String : public Primitive { * method of the object) then the length() method returns 0 and the * operator * returns NULL. */ - class V8_EXPORT AsciiValue { + class V8EXPORT AsciiValue { public: // TODO(dcarney): deprecate explicit AsciiValue(Handle<v8::Value> obj); @@ -1905,7 +1876,7 @@ class V8_EXPORT String : public Primitive { * method of the object) then the length() method returns 0 and the * operator * returns NULL. */ - class V8_EXPORT Value { + class V8EXPORT Value { public: explicit Value(Handle<v8::Value> obj); ~Value(); @@ -1934,7 +1905,7 @@ class V8_EXPORT String : public Primitive { * * This is an experimental feature. Use at your own risk. */ -class V8_EXPORT Symbol : public Primitive { +class V8EXPORT Symbol : public Primitive { public: // Returns the print name string of the symbol, or undefined if none. Local<Value> Name() const; @@ -1955,7 +1926,7 @@ class V8_EXPORT Symbol : public Primitive { /** * A JavaScript number value (ECMA-262, 4.3.20) */ -class V8_EXPORT Number : public Primitive { +class V8EXPORT Number : public Primitive { public: double Value() const; static Local<Number> New(double value); @@ -1970,7 +1941,7 @@ class V8_EXPORT Number : public Primitive { /** * A JavaScript value representing a signed integer. */ -class V8_EXPORT Integer : public Number { +class V8EXPORT Integer : public Number { public: static Local<Integer> New(int32_t value); static Local<Integer> NewFromUnsigned(uint32_t value); @@ -1987,7 +1958,7 @@ class V8_EXPORT Integer : public Number { /** * A JavaScript value representing a 32-bit signed integer. */ -class V8_EXPORT Int32 : public Integer { +class V8EXPORT Int32 : public Integer { public: int32_t Value() const; private: @@ -1998,7 +1969,7 @@ class V8_EXPORT Int32 : public Integer { /** * A JavaScript value representing a 32-bit unsigned integer. */ -class V8_EXPORT Uint32 : public Integer { +class V8EXPORT Uint32 : public Integer { public: uint32_t Value() const; private: @@ -2070,7 +2041,7 @@ enum AccessControl { /** * A JavaScript object (ECMA-262, 4.3.3) */ -class V8_EXPORT Object : public Value { +class V8EXPORT Object : public Value { public: bool Set(Handle<Value> key, Handle<Value> value, @@ -2342,7 +2313,7 @@ class V8_EXPORT Object : public Value { /** * An instance of the built-in array constructor (ECMA-262, 15.4.2). */ -class V8_EXPORT Array : public Object { +class V8EXPORT Array : public Object { public: uint32_t Length() const; @@ -2368,7 +2339,7 @@ class V8_EXPORT Array : public Object { /** * A JavaScript function object (ECMA-262, 15.3). */ -class V8_EXPORT Function : public Object { +class V8EXPORT Function : public Object { public: Local<Object> NewInstance() const; Local<Object> NewInstance(int argc, Handle<Value> argv[]) const; @@ -2424,7 +2395,7 @@ class V8_EXPORT Function : public Object { * An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5). * This API is experimental and may change significantly. */ -class V8_EXPORT ArrayBuffer : public Object { +class V8EXPORT ArrayBuffer : public Object { public: /** * Allocator that V8 uses to allocate |ArrayBuffer|'s memory. @@ -2433,7 +2404,7 @@ class V8_EXPORT ArrayBuffer : public Object { * * This API is experimental and may change significantly. */ - class V8_EXPORT Allocator { // NOLINT + class V8EXPORT Allocator { // NOLINT public: virtual ~Allocator() {} @@ -2480,7 +2451,7 @@ class V8_EXPORT ArrayBuffer : public Object { * * This API is experimental and may change significantly. */ - class V8_EXPORT Contents { // NOLINT + class V8EXPORT Contents { // NOLINT public: Contents() : data_(NULL), byte_length_(0) {} @@ -2563,7 +2534,7 @@ class V8_EXPORT ArrayBuffer : public Object { * * This API is experimental and may change significantly. */ -class V8_EXPORT ArrayBufferView : public Object { +class V8EXPORT ArrayBufferView : public Object { public: /** * Returns underlying ArrayBuffer. @@ -2598,7 +2569,7 @@ class V8_EXPORT ArrayBufferView : public Object { * (ES6 draft 15.13.6). * This API is experimental and may change significantly. */ -class V8_EXPORT TypedArray : public ArrayBufferView { +class V8EXPORT TypedArray : public ArrayBufferView { public: /** * Number of elements in this typed array @@ -2618,7 +2589,7 @@ class V8_EXPORT TypedArray : public ArrayBufferView { * An instance of Uint8Array constructor (ES6 draft 15.13.6). * This API is experimental and may change significantly. */ -class V8_EXPORT Uint8Array : public TypedArray { +class V8EXPORT Uint8Array : public TypedArray { public: static Local<Uint8Array> New(Handle<ArrayBuffer> array_buffer, size_t byte_offset, size_t length); @@ -2634,7 +2605,7 @@ class V8_EXPORT Uint8Array : public TypedArray { * An instance of Uint8ClampedArray constructor (ES6 draft 15.13.6). * This API is experimental and may change significantly. */ -class V8_EXPORT Uint8ClampedArray : public TypedArray { +class V8EXPORT Uint8ClampedArray : public TypedArray { public: static Local<Uint8ClampedArray> New(Handle<ArrayBuffer> array_buffer, size_t byte_offset, size_t length); @@ -2649,7 +2620,7 @@ class V8_EXPORT Uint8ClampedArray : public TypedArray { * An instance of Int8Array constructor (ES6 draft 15.13.6). * This API is experimental and may change significantly. */ -class V8_EXPORT Int8Array : public TypedArray { +class V8EXPORT Int8Array : public TypedArray { public: static Local<Int8Array> New(Handle<ArrayBuffer> array_buffer, size_t byte_offset, size_t length); @@ -2665,7 +2636,7 @@ class V8_EXPORT Int8Array : public TypedArray { * An instance of Uint16Array constructor (ES6 draft 15.13.6). * This API is experimental and may change significantly. */ -class V8_EXPORT Uint16Array : public TypedArray { +class V8EXPORT Uint16Array : public TypedArray { public: static Local<Uint16Array> New(Handle<ArrayBuffer> array_buffer, size_t byte_offset, size_t length); @@ -2681,7 +2652,7 @@ class V8_EXPORT Uint16Array : public TypedArray { * An instance of Int16Array constructor (ES6 draft 15.13.6). * This API is experimental and may change significantly. */ -class V8_EXPORT Int16Array : public TypedArray { +class V8EXPORT Int16Array : public TypedArray { public: static Local<Int16Array> New(Handle<ArrayBuffer> array_buffer, size_t byte_offset, size_t length); @@ -2697,7 +2668,7 @@ class V8_EXPORT Int16Array : public TypedArray { * An instance of Uint32Array constructor (ES6 draft 15.13.6). * This API is experimental and may change significantly. */ -class V8_EXPORT Uint32Array : public TypedArray { +class V8EXPORT Uint32Array : public TypedArray { public: static Local<Uint32Array> New(Handle<ArrayBuffer> array_buffer, size_t byte_offset, size_t length); @@ -2713,7 +2684,7 @@ class V8_EXPORT Uint32Array : public TypedArray { * An instance of Int32Array constructor (ES6 draft 15.13.6). * This API is experimental and may change significantly. */ -class V8_EXPORT Int32Array : public TypedArray { +class V8EXPORT Int32Array : public TypedArray { public: static Local<Int32Array> New(Handle<ArrayBuffer> array_buffer, size_t byte_offset, size_t length); @@ -2729,7 +2700,7 @@ class V8_EXPORT Int32Array : public TypedArray { * An instance of Float32Array constructor (ES6 draft 15.13.6). * This API is experimental and may change significantly. */ -class V8_EXPORT Float32Array : public TypedArray { +class V8EXPORT Float32Array : public TypedArray { public: static Local<Float32Array> New(Handle<ArrayBuffer> array_buffer, size_t byte_offset, size_t length); @@ -2745,7 +2716,7 @@ class V8_EXPORT Float32Array : public TypedArray { * An instance of Float64Array constructor (ES6 draft 15.13.6). * This API is experimental and may change significantly. */ -class V8_EXPORT Float64Array : public TypedArray { +class V8EXPORT Float64Array : public TypedArray { public: static Local<Float64Array> New(Handle<ArrayBuffer> array_buffer, size_t byte_offset, size_t length); @@ -2761,7 +2732,7 @@ class V8_EXPORT Float64Array : public TypedArray { * An instance of DataView constructor (ES6 draft 15.13.7). * This API is experimental and may change significantly. */ -class V8_EXPORT DataView : public ArrayBufferView { +class V8EXPORT DataView : public ArrayBufferView { public: static Local<DataView> New(Handle<ArrayBuffer> array_buffer, size_t byte_offset, size_t length); @@ -2776,7 +2747,7 @@ class V8_EXPORT DataView : public ArrayBufferView { /** * An instance of the built-in Date constructor (ECMA-262, 15.9). */ -class V8_EXPORT Date : public Object { +class V8EXPORT Date : public Object { public: static Local<Value> New(double time); @@ -2814,7 +2785,7 @@ class V8_EXPORT Date : public Object { /** * A Number object (ECMA-262, 4.3.21). */ -class V8_EXPORT NumberObject : public Object { +class V8EXPORT NumberObject : public Object { public: static Local<Value> New(double value); @@ -2837,7 +2808,7 @@ class V8_EXPORT NumberObject : public Object { /** * A Boolean object (ECMA-262, 4.3.15). */ -class V8_EXPORT BooleanObject : public Object { +class V8EXPORT BooleanObject : public Object { public: static Local<Value> New(bool value); @@ -2860,7 +2831,7 @@ class V8_EXPORT BooleanObject : public Object { /** * A String object (ECMA-262, 4.3.18). */ -class V8_EXPORT StringObject : public Object { +class V8EXPORT StringObject : public Object { public: static Local<Value> New(Handle<String> value); @@ -2885,7 +2856,7 @@ class V8_EXPORT StringObject : public Object { * * This is an experimental feature. Use at your own risk. */ -class V8_EXPORT SymbolObject : public Object { +class V8EXPORT SymbolObject : public Object { public: static Local<Value> New(Isolate* isolate, Handle<Symbol> value); @@ -2908,7 +2879,7 @@ class V8_EXPORT SymbolObject : public Object { /** * An instance of the built-in RegExp constructor (ECMA-262, 15.10). */ -class V8_EXPORT RegExp : public Object { +class V8EXPORT RegExp : public Object { public: /** * Regular expression flag bits. They can be or'ed to enable a set @@ -2955,7 +2926,7 @@ class V8_EXPORT RegExp : public Object { * A JavaScript value that wraps a C++ void*. This type of value is mainly used * to associate C++ data structures with JavaScript objects. */ -class V8_EXPORT External : public Value { +class V8EXPORT External : public Value { public: static Local<External> New(void* value); V8_INLINE(static External* Cast(Value* obj)); @@ -2971,7 +2942,7 @@ class V8_EXPORT External : public Value { /** * The superclass of object and function templates. */ -class V8_EXPORT Template : public Data { +class V8EXPORT Template : public Data { public: /** Adds a property to each instance created by this template.*/ void Set(Handle<String> name, Handle<Data> value, @@ -3059,7 +3030,7 @@ class FunctionCallbackInfo { }; -class V8_EXPORT Arguments : public FunctionCallbackInfo<Value> { +class V8EXPORT Arguments : public FunctionCallbackInfo<Value> { private: friend class internal::FunctionCallbackArguments; V8_INLINE(Arguments(internal::Object** implicit_args, @@ -3100,7 +3071,7 @@ class PropertyCallbackInfo { }; -class V8_EXPORT AccessorInfo : public PropertyCallbackInfo<Value> { +class V8EXPORT AccessorInfo : public PropertyCallbackInfo<Value> { private: friend class internal::PropertyCallbackArguments; V8_INLINE(AccessorInfo(internal::Object** args)) @@ -3348,7 +3319,7 @@ typedef bool (*IndexedSecurityCallback)(Local<Object> host, * child_instance.instance_property == 3; * \endcode */ -class V8_EXPORT FunctionTemplate : public Template { +class V8EXPORT FunctionTemplate : public Template { public: /** Creates a function template.*/ V8_DEPRECATED(static Local<FunctionTemplate> New( @@ -3439,7 +3410,7 @@ class V8_EXPORT FunctionTemplate : public Template { * Properties added to an ObjectTemplate are added to each object * created from the ObjectTemplate. */ -class V8_EXPORT ObjectTemplate : public Template { +class V8EXPORT ObjectTemplate : public Template { public: /** Creates an ObjectTemplate. */ static Local<ObjectTemplate> New(); @@ -3625,7 +3596,7 @@ class V8_EXPORT ObjectTemplate : public Template { * A Signature specifies which receivers and arguments are valid * parameters to a function. */ -class V8_EXPORT Signature : public Data { +class V8EXPORT Signature : public Data { public: static Local<Signature> New(Handle<FunctionTemplate> receiver = Handle<FunctionTemplate>(), @@ -3640,7 +3611,7 @@ class V8_EXPORT Signature : public Data { * An AccessorSignature specifies which receivers are valid parameters * to an accessor callback. */ -class V8_EXPORT AccessorSignature : public Data { +class V8EXPORT AccessorSignature : public Data { public: static Local<AccessorSignature> New(Handle<FunctionTemplate> receiver = Handle<FunctionTemplate>()); @@ -3649,13 +3620,13 @@ class V8_EXPORT AccessorSignature : public Data { }; -class V8_EXPORT DeclaredAccessorDescriptor : public Data { +class V8EXPORT DeclaredAccessorDescriptor : public Data { private: DeclaredAccessorDescriptor(); }; -class V8_EXPORT ObjectOperationDescriptor : public Data { +class V8EXPORT ObjectOperationDescriptor : public Data { public: // This function is not yet stable and should not be used at this time. static Local<RawOperationDescriptor> NewInternalFieldDereference( @@ -3675,7 +3646,7 @@ enum DeclaredAccessorDescriptorDataType { }; -class V8_EXPORT RawOperationDescriptor : public Data { +class V8EXPORT RawOperationDescriptor : public Data { public: Local<DeclaredAccessorDescriptor> NewHandleDereference(Isolate* isolate); Local<RawOperationDescriptor> NewRawDereference(Isolate* isolate); @@ -3708,7 +3679,7 @@ class V8_EXPORT RawOperationDescriptor : public Data { * A utility for determining the type of objects based on the template * they were constructed from. */ -class V8_EXPORT TypeSwitch : public Data { +class V8EXPORT TypeSwitch : public Data { public: static Local<TypeSwitch> New(Handle<FunctionTemplate> type); static Local<TypeSwitch> New(int argc, Handle<FunctionTemplate> types[]); @@ -3720,7 +3691,7 @@ class V8_EXPORT TypeSwitch : public Data { // --- Extensions --- -class V8_EXPORT ExternalAsciiStringResourceImpl +class V8EXPORT ExternalAsciiStringResourceImpl : public String::ExternalAsciiStringResource { public: ExternalAsciiStringResourceImpl() : data_(0), length_(0) {} @@ -3737,7 +3708,7 @@ class V8_EXPORT ExternalAsciiStringResourceImpl /** * Ignore */ -class V8_EXPORT Extension { // NOLINT +class V8EXPORT Extension { // NOLINT public: // Note that the strings passed into this constructor must live as long // as the Extension itself. @@ -3775,13 +3746,13 @@ class V8_EXPORT Extension { // NOLINT }; -void V8_EXPORT RegisterExtension(Extension* extension); +void V8EXPORT RegisterExtension(Extension* extension); /** * Ignore */ -class V8_EXPORT DeclareExtension { +class V8EXPORT DeclareExtension { public: V8_INLINE(DeclareExtension(Extension* extension)) { RegisterExtension(extension); @@ -3792,10 +3763,10 @@ class V8_EXPORT DeclareExtension { // --- Statics --- -Handle<Primitive> V8_EXPORT Undefined(); -Handle<Primitive> V8_EXPORT Null(); -Handle<Boolean> V8_EXPORT True(); -Handle<Boolean> V8_EXPORT False(); +Handle<Primitive> V8EXPORT Undefined(); +Handle<Primitive> V8EXPORT Null(); +Handle<Boolean> V8EXPORT True(); +Handle<Boolean> V8EXPORT False(); V8_INLINE(Handle<Primitive> Undefined(Isolate* isolate)); V8_INLINE(Handle<Primitive> Null(Isolate* isolate)); @@ -3812,7 +3783,7 @@ V8_INLINE(Handle<Boolean> False(Isolate* isolate)); * setting the stack limit and you must set a non-default stack limit separately * for each thread. */ -class V8_EXPORT ResourceConstraints { +class V8EXPORT ResourceConstraints { public: ResourceConstraints(); int max_young_space_size() const { return max_young_space_size_; } @@ -3832,7 +3803,7 @@ class V8_EXPORT ResourceConstraints { }; -bool V8_EXPORT SetResourceConstraints(ResourceConstraints* constraints); +bool V8EXPORT SetResourceConstraints(ResourceConstraints* constraints); // --- Exceptions --- @@ -3850,13 +3821,13 @@ typedef void (*MessageCallback)(Handle<Message> message, Handle<Value> error); * operation; the caller must return immediately and only after the exception * has been handled does it become legal to invoke JavaScript operations. */ -Handle<Value> V8_EXPORT ThrowException(Handle<Value> exception); +Handle<Value> V8EXPORT ThrowException(Handle<Value> exception); /** * Create new error objects by calling the corresponding error object * constructor with the message. */ -class V8_EXPORT Exception { +class V8EXPORT Exception { public: static Local<Value> RangeError(Handle<String> message); static Local<Value> ReferenceError(Handle<String> message); @@ -3950,7 +3921,7 @@ typedef void (*GCCallback)(); * Instances of this class can be passed to v8::V8::HeapStatistics to * get heap statistics from V8. */ -class V8_EXPORT HeapStatistics { +class V8EXPORT HeapStatistics { public: HeapStatistics(); size_t total_heap_size() { return total_heap_size_; } @@ -3982,13 +3953,13 @@ class RetainedObjectInfo; * threads. An isolate can be entered by at most one thread at any * given time. The Locker/Unlocker API must be used to synchronize. */ -class V8_EXPORT Isolate { +class V8EXPORT Isolate { public: /** * Stack-allocated class which sets the isolate for all operations * executed within a local scope. */ - class V8_EXPORT Scope { + class V8EXPORT Scope { public: explicit Scope(Isolate* isolate) : isolate_(isolate) { isolate->Enter(); @@ -4136,7 +4107,7 @@ class V8_EXPORT Isolate { }; -class V8_EXPORT StartupData { +class V8EXPORT StartupData { public: enum CompressionAlgorithm { kUncompressed, @@ -4157,7 +4128,7 @@ class V8_EXPORT StartupData { * * For an example of the class usage, see the "shell.cc" sample application. */ -class V8_EXPORT StartupDataDecompressor { // NOLINT +class V8EXPORT StartupDataDecompressor { // NOLINT public: StartupDataDecompressor(); virtual ~StartupDataDecompressor(); @@ -4301,7 +4272,7 @@ typedef void (*JitCodeEventHandler)(const JitCodeEvent* event); /** * Interface for iterating through all external resources in the heap. */ -class V8_EXPORT ExternalResourceVisitor { // NOLINT +class V8EXPORT ExternalResourceVisitor { // NOLINT public: virtual ~ExternalResourceVisitor() {} virtual void VisitExternalString(Handle<String> string) {} @@ -4311,7 +4282,7 @@ class V8_EXPORT ExternalResourceVisitor { // NOLINT /** * Interface for iterating through all the persistent handles in the heap. */ -class V8_EXPORT PersistentHandleVisitor { // NOLINT +class V8EXPORT PersistentHandleVisitor { // NOLINT public: virtual ~PersistentHandleVisitor() {} virtual void VisitPersistentHandle(Persistent<Value>* value, @@ -4324,7 +4295,7 @@ class V8_EXPORT PersistentHandleVisitor { // NOLINT * to be modified. Useful when otherwise unsafe handle operations need to * be performed. */ -class V8_EXPORT AssertNoGCScope { +class V8EXPORT AssertNoGCScope { #ifndef DEBUG // TODO(yangguo): remove isolate argument. V8_INLINE(AssertNoGCScope(Isolate* isolate)) { } @@ -4340,7 +4311,7 @@ class V8_EXPORT AssertNoGCScope { /** * Container class for static utility functions. */ -class V8_EXPORT V8 { +class V8EXPORT V8 { public: /** Set the callback to invoke in case of fatal errors. */ static void SetFatalErrorHandler(FatalErrorCallback that); @@ -4797,9 +4768,6 @@ class V8_EXPORT V8 { void* data, RevivableCallback weak_reference_callback); static void ClearWeak(internal::Object** global_handle); - static int Eternalize(internal::Isolate* isolate, - internal::Object** handle); - static internal::Object** GetEternal(internal::Isolate* isolate, int index); template <class T> friend class Handle; template <class T> friend class Local; @@ -4811,7 +4779,7 @@ class V8_EXPORT V8 { /** * An external exception handler. */ -class V8_EXPORT TryCatch { +class V8EXPORT TryCatch { public: /** * Creates a new try/catch block and registers it with v8. Note that @@ -4944,7 +4912,7 @@ class V8_EXPORT TryCatch { /** * Ignore */ -class V8_EXPORT ExtensionConfiguration { +class V8EXPORT ExtensionConfiguration { public: ExtensionConfiguration(int name_count, const char* names[]) : name_count_(name_count), names_(names) { } @@ -4959,7 +4927,7 @@ class V8_EXPORT ExtensionConfiguration { * A sandboxed execution context with its own set of built-in objects * and functions. */ -class V8_EXPORT Context { +class V8EXPORT Context { public: /** * Returns the global proxy object or global object itself for @@ -5244,7 +5212,7 @@ class V8_EXPORT Context { * // V8 Now no longer locked. * \endcode */ -class V8_EXPORT Unlocker { +class V8EXPORT Unlocker { public: /** * Initialize Unlocker for a given Isolate. @@ -5262,7 +5230,7 @@ class V8_EXPORT Unlocker { }; -class V8_EXPORT Locker { +class V8EXPORT Locker { public: /** * Initialize Locker for a given Isolate. @@ -5323,7 +5291,7 @@ struct HeapStatsUpdate; /** * An interface for exporting data from V8, using "push" model. */ -class V8_EXPORT OutputStream { // NOLINT +class V8EXPORT OutputStream { // NOLINT public: enum OutputEncoding { kAscii = 0 // 7-bit ASCII. @@ -5360,7 +5328,7 @@ class V8_EXPORT OutputStream { // NOLINT * An interface for reporting progress and controlling long-running * activities. */ -class V8_EXPORT ActivityControl { // NOLINT +class V8EXPORT ActivityControl { // NOLINT public: enum ControlOption { kContinue = 0, @@ -5483,7 +5451,7 @@ class Internals { static const int kNullValueRootIndex = 7; static const int kTrueValueRootIndex = 8; static const int kFalseValueRootIndex = 9; - static const int kEmptyStringRootIndex = 133; + static const int kEmptyStringRootIndex = 135; static const int kNodeClassIdOffset = 1 * kApiPointerSize; static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3; @@ -5544,14 +5512,14 @@ class Internals { V8_INLINE(static uint8_t GetNodeFlag(internal::Object** obj, int shift)) { uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset; - return *addr & static_cast<uint8_t>(1U << shift); + return *addr & (1 << shift); } V8_INLINE(static void UpdateNodeFlag(internal::Object** obj, bool value, int shift)) { uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset; - uint8_t mask = static_cast<uint8_t>(1 << shift); - *addr = static_cast<uint8_t>((*addr & ~mask) | (value << shift)); + uint8_t mask = 1 << shift; + *addr = (*addr & ~mask) | (value << shift); } V8_INLINE(static uint8_t GetNodeState(internal::Object** obj)) { @@ -5562,7 +5530,7 @@ class Internals { V8_INLINE(static void UpdateNodeState(internal::Object** obj, uint8_t value)) { uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset; - *addr = static_cast<uint8_t>((*addr & ~kNodeStateMask) | value); + *addr = (*addr & ~kNodeStateMask) | value; } V8_INLINE(static void SetEmbedderData(v8::Isolate* isolate, void* data)) { @@ -5663,21 +5631,6 @@ Local<T> Local<T>::New(Isolate* isolate, T* that) { } -template<class T> -int Local<T>::Eternalize(Isolate* isolate) { - return V8::Eternalize(reinterpret_cast<internal::Isolate*>(isolate), - reinterpret_cast<internal::Object**>(this->val_)); -} - - -template<class T> -Local<T> Local<T>::GetEternal(Isolate* isolate, int index) { - internal::Object** handle = - V8::GetEternal(reinterpret_cast<internal::Isolate*>(isolate), index); - return Local<T>(T::Cast(reinterpret_cast<Value*>(handle))); -} - - #ifdef V8_USE_UNSAFE_HANDLES template <class T> Persistent<T> Persistent<T>::New(Handle<T> that) { @@ -5927,7 +5880,7 @@ void ReturnValue<T>::Set(uint32_t i) { TYPE_CHECK(T, Integer); typedef internal::Internals I; // Can't simply use INT32_MAX here for whatever reason. - bool fits_into_int32_t = (i & (1U << 31)) == 0; + bool fits_into_int32_t = (i & (1 << 31)) == 0; if (V8_LIKELY(fits_into_int32_t)) { Set(static_cast<int32_t>(i)); return; @@ -6589,6 +6542,7 @@ void* Context::GetAlignedPointerFromEmbedderData(int index) { } // namespace v8 +#undef V8EXPORT #undef TYPE_CHECK diff --git a/chromium/v8/src/api.cc b/chromium/v8/src/api.cc index eb2ffcff180..7b2524cc4d7 100644 --- a/chromium/v8/src/api.cc +++ b/chromium/v8/src/api.cc @@ -46,7 +46,6 @@ #include "heap-profiler.h" #include "heap-snapshot-generator-inl.h" #include "icu_util.h" -#include "json-parser.h" #include "messages.h" #ifdef COMPRESS_STARTUP_DATA_BZ2 #include "natives.h" @@ -676,16 +675,6 @@ void V8::DisposeGlobal(i::Object** obj) { } -int V8::Eternalize(i::Isolate* isolate, i::Object** handle) { - return isolate->eternal_handles()->Create(isolate, *handle); -} - - -i::Object** V8::GetEternal(i::Isolate* isolate, int index) { - return isolate->eternal_handles()->Get(index).location(); -} - - // --- H a n d l e s --- @@ -781,6 +770,7 @@ void Context::Exit() { i::Context* last_context = isolate->handle_scope_implementer()->RestoreContext(); isolate->set_context(last_context); + isolate->set_context_exit_happened(true); } @@ -2617,29 +2607,6 @@ bool StackFrame::IsConstructor() const { } -// --- J S O N --- - -Local<Value> JSON::Parse(Local<String> json_string) { - i::Isolate* isolate = i::Isolate::Current(); - EnsureInitializedForIsolate(isolate, "v8::JSON::Parse"); - ENTER_V8(isolate); - i::HandleScope scope(isolate); - i::Handle<i::String> source = i::Handle<i::String>( - FlattenGetString(Utils::OpenHandle(*json_string))); - EXCEPTION_PREAMBLE(isolate); - i::Handle<i::Object> result; - if (source->IsSeqOneByteString()) { - result = i::JsonParser<true>::Parse(source); - } else { - result = i::JsonParser<false>::Parse(source); - } - has_pending_exception = result.is_null(); - EXCEPTION_BAILOUT_CHECK(isolate, Local<Object>()); - return Utils::ToLocal( - i::Handle<i::Object>::cast(scope.CloseAndEscape(result))); -} - - // --- D a t a --- bool Value::FullIsUndefined() const { @@ -7477,6 +7444,8 @@ Handle<String> CpuProfileNode::GetFunctionName() const { int CpuProfileNode::GetScriptId() const { + i::Isolate* isolate = i::Isolate::Current(); + IsDeadCheck(isolate, "v8::CpuProfileNode::GetScriptId"); const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this); const i::CodeEntry* entry = node->entry(); return entry->script_id(); @@ -7493,6 +7462,8 @@ Handle<String> CpuProfileNode::GetScriptResourceName() const { int CpuProfileNode::GetLineNumber() const { + i::Isolate* isolate = i::Isolate::Current(); + IsDeadCheck(isolate, "v8::CpuProfileNode::GetLineNumber"); return reinterpret_cast<const i::ProfileNode*>(this)->entry()->line_number(); } @@ -7525,12 +7496,9 @@ double CpuProfileNode::GetSelfSamplesCount() const { } -unsigned CpuProfileNode::GetHitCount() const { - return reinterpret_cast<const i::ProfileNode*>(this)->self_ticks(); -} - - unsigned CpuProfileNode::GetCallUid() const { + i::Isolate* isolate = i::Isolate::Current(); + IsDeadCheck(isolate, "v8::CpuProfileNode::GetCallUid"); return reinterpret_cast<const i::ProfileNode*>(this)->entry()->GetCallUid(); } @@ -7541,11 +7509,15 @@ unsigned CpuProfileNode::GetNodeId() const { int CpuProfileNode::GetChildrenCount() const { + i::Isolate* isolate = i::Isolate::Current(); + IsDeadCheck(isolate, "v8::CpuProfileNode::GetChildrenCount"); return reinterpret_cast<const i::ProfileNode*>(this)->children()->length(); } const CpuProfileNode* CpuProfileNode::GetChild(int index) const { + i::Isolate* isolate = i::Isolate::Current(); + IsDeadCheck(isolate, "v8::CpuProfileNode::GetChild"); const i::ProfileNode* child = reinterpret_cast<const i::ProfileNode*>(this)->children()->at(index); return reinterpret_cast<const CpuProfileNode*>(child); @@ -7566,6 +7538,8 @@ void CpuProfile::Delete() { unsigned CpuProfile::GetUid() const { + i::Isolate* isolate = i::Isolate::Current(); + IsDeadCheck(isolate, "v8::CpuProfile::GetUid"); return reinterpret_cast<const i::CpuProfile*>(this)->uid(); } @@ -7580,6 +7554,8 @@ Handle<String> CpuProfile::GetTitle() const { const CpuProfileNode* CpuProfile::GetTopDownRoot() const { + i::Isolate* isolate = i::Isolate::Current(); + IsDeadCheck(isolate, "v8::CpuProfile::GetTopDownRoot"); const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this); return reinterpret_cast<const CpuProfileNode*>(profile->top_down()->root()); } @@ -7637,19 +7613,6 @@ void CpuProfiler::DeleteAllCpuProfiles() { } -void CpuProfiler::SetIdle(bool is_idle) { - i::Isolate* isolate = reinterpret_cast<i::CpuProfiler*>(this)->isolate(); - i::StateTag state = isolate->current_vm_state(); - ASSERT(state == i::EXTERNAL || state == i::IDLE); - if (isolate->js_entry_sp() != NULL) return; - if (is_idle) { - isolate->set_current_vm_state(i::IDLE); - } else if (state == i::IDLE) { - isolate->set_current_vm_state(i::EXTERNAL); - } -} - - static i::HeapGraphEdge* ToInternal(const HeapGraphEdge* edge) { return const_cast<i::HeapGraphEdge*>( reinterpret_cast<const i::HeapGraphEdge*>(edge)); diff --git a/chromium/v8/src/arm/builtins-arm.cc b/chromium/v8/src/arm/builtins-arm.cc index 5f3a999f561..eff47e2692b 100644 --- a/chromium/v8/src/arm/builtins-arm.cc +++ b/chromium/v8/src/arm/builtins-arm.cc @@ -119,9 +119,9 @@ void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { // Initial map for the builtin InternalArray functions should be maps. __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); __ SmiTst(r2); - __ Assert(ne, kUnexpectedInitialMapForInternalArrayFunction); + __ Assert(ne, "Unexpected initial map for InternalArray function"); __ CompareObjectType(r2, r3, r4, MAP_TYPE); - __ Assert(eq, kUnexpectedInitialMapForInternalArrayFunction); + __ Assert(eq, "Unexpected initial map for InternalArray function"); } // Run the native code for the InternalArray function called as a normal @@ -147,9 +147,9 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { // Initial map for the builtin Array functions should be maps. __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); __ SmiTst(r2); - __ Assert(ne, kUnexpectedInitialMapForArrayFunction); + __ Assert(ne, "Unexpected initial map for Array function"); __ CompareObjectType(r2, r3, r4, MAP_TYPE); - __ Assert(eq, kUnexpectedInitialMapForArrayFunction); + __ Assert(eq, "Unexpected initial map for Array function"); } // Run the native code for the Array function called as a normal function. @@ -178,7 +178,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { if (FLAG_debug_code) { __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, r2); __ cmp(function, Operand(r2)); - __ Assert(eq, kUnexpectedStringFunction); + __ Assert(eq, "Unexpected String function"); } // Load the first arguments in r0 and get rid of the rest. @@ -224,10 +224,10 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { if (FLAG_debug_code) { __ ldrb(r4, FieldMemOperand(map, Map::kInstanceSizeOffset)); __ cmp(r4, Operand(JSValue::kSize >> kPointerSizeLog2)); - __ Assert(eq, kUnexpectedStringWrapperInstanceSize); + __ Assert(eq, "Unexpected string wrapper instance size"); __ ldrb(r4, FieldMemOperand(map, Map::kUnusedPropertyFieldsOffset)); __ cmp(r4, Operand::Zero()); - __ Assert(eq, kUnexpectedUnusedPropertiesOfStringWrapper); + __ Assert(eq, "Unexpected unused properties of string wrapper"); } __ str(map, FieldMemOperand(r0, HeapObject::kMapOffset)); @@ -471,7 +471,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // r0: offset of first field after pre-allocated fields if (FLAG_debug_code) { __ cmp(r0, r6); - __ Assert(le, kUnexpectedNumberOfPreAllocatedPropertyFields); + __ Assert(le, "Unexpected number of pre-allocated property fields."); } __ InitializeFieldsWithFiller(r5, r0, r7); // To allow for truncation. @@ -503,7 +503,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // Done if no extra properties are to be allocated. __ b(eq, &allocated); - __ Assert(pl, kPropertyAllocationCountFailed); + __ Assert(pl, "Property allocation count failed."); // Scale the number of elements by pointer size and add the header for // FixedArrays to the start of the next object calculation from above. @@ -547,7 +547,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, } else if (FLAG_debug_code) { __ LoadRoot(r8, Heap::kUndefinedValueRootIndex); __ cmp(r7, r8); - __ Assert(eq, kUndefinedValueNotLoaded); + __ Assert(eq, "Undefined value not loaded."); } __ b(&entry); __ bind(&loop); diff --git a/chromium/v8/src/arm/code-stubs-arm.cc b/chromium/v8/src/arm/code-stubs-arm.cc index 98a835fd1a5..ba98b963153 100644 --- a/chromium/v8/src/arm/code-stubs-arm.cc +++ b/chromium/v8/src/arm/code-stubs-arm.cc @@ -246,6 +246,17 @@ void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( } +void UnaryOpStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + static Register registers[] = { r0 }; + descriptor->register_param_count_ = 1; + descriptor->register_params_ = registers; + descriptor->deoptimization_handler_ = + FUNCTION_ADDR(UnaryOpIC_Miss); +} + + void StoreGlobalStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { @@ -509,8 +520,9 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) { Label after_sentinel; __ JumpIfNotSmi(r3, &after_sentinel); if (FLAG_debug_code) { + const char* message = "Expected 0 as a Smi sentinel"; __ cmp(r3, Operand::Zero()); - __ Assert(eq, kExpected0AsASmiSentinel); + __ Assert(eq, message); } __ ldr(r3, GlobalObjectOperand()); __ ldr(r3, FieldMemOperand(r3, GlobalObject::kNativeContextOffset)); @@ -3905,9 +3917,9 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ ldr(regexp_data, FieldMemOperand(r0, JSRegExp::kDataOffset)); if (FLAG_debug_code) { __ SmiTst(regexp_data); - __ Check(ne, kUnexpectedTypeForRegExpDataFixedArrayExpected); + __ Check(ne, "Unexpected type for RegExp data, FixedArray expected"); __ CompareObjectType(regexp_data, r0, r0, FIXED_ARRAY_TYPE); - __ Check(eq, kUnexpectedTypeForRegExpDataFixedArrayExpected); + __ Check(eq, "Unexpected type for RegExp data, FixedArray expected"); } // regexp_data: RegExp data (FixedArray) @@ -4249,7 +4261,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // Assert that we do not have a cons or slice (indirect strings) here. // Sequential strings have already been ruled out. __ tst(r0, Operand(kIsIndirectStringMask)); - __ Assert(eq, kExternalStringExpectedButNotFound); + __ Assert(eq, "external string expected, but not found"); } __ ldr(subject, FieldMemOperand(subject, ExternalString::kResourceDataOffset)); @@ -4631,7 +4643,7 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { void StringCharCodeAtGenerator::GenerateSlow( MacroAssembler* masm, const RuntimeCallHelper& call_helper) { - __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase); + __ Abort("Unexpected fallthrough to CharCodeAt slow case"); // Index is not a smi. __ bind(&index_not_smi_); @@ -4676,7 +4688,7 @@ void StringCharCodeAtGenerator::GenerateSlow( call_helper.AfterCall(masm); __ jmp(&exit_); - __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase); + __ Abort("Unexpected fallthrough from CharCodeAt slow case"); } @@ -4706,7 +4718,7 @@ void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { void StringCharFromCodeGenerator::GenerateSlow( MacroAssembler* masm, const RuntimeCallHelper& call_helper) { - __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase); + __ Abort("Unexpected fallthrough to CharFromCode slow case"); __ bind(&slow_case_); call_helper.BeforeCall(masm); @@ -4716,7 +4728,7 @@ void StringCharFromCodeGenerator::GenerateSlow( call_helper.AfterCall(masm); __ jmp(&exit_); - __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); + __ Abort("Unexpected fallthrough from CharFromCode slow case"); } @@ -4773,7 +4785,7 @@ void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm, // Check that destination is actually word aligned if the flag says // that it is. __ tst(dest, Operand(kPointerAlignmentMask)); - __ Check(eq, kDestinationOfCopyNotAligned); + __ Check(eq, "Destination of copy not aligned."); } const int kReadAlignment = 4; @@ -5002,7 +5014,7 @@ void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, if (FLAG_debug_code) { __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); __ cmp(ip, candidate); - __ Assert(eq, kOddballInStringTableIsNotUndefinedOrTheHole); + __ Assert(eq, "oddball in string table is not undefined or the hole"); } __ jmp(&next_probe[i]); @@ -6900,7 +6912,7 @@ static void CreateArrayDispatch(MacroAssembler* masm) { } // If we reached this point there is a problem. - __ Abort(kUnexpectedElementsKindInArrayConstructor); + __ Abort("Unexpected ElementsKind in array constructor"); } @@ -6957,7 +6969,7 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm) { } // If we reached this point there is a problem. - __ Abort(kUnexpectedElementsKindInArrayConstructor); + __ Abort("Unexpected ElementsKind in array constructor"); } @@ -7018,9 +7030,9 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) { __ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); // Will both indicate a NULL and a Smi. __ tst(r3, Operand(kSmiTagMask)); - __ Assert(ne, kUnexpectedInitialMapForArrayFunction); + __ Assert(ne, "Unexpected initial map for Array function"); __ CompareObjectType(r3, r3, r4, MAP_TYPE); - __ Assert(eq, kUnexpectedInitialMapForArrayFunction); + __ Assert(eq, "Unexpected initial map for Array function"); // We should either have undefined in ebx or a valid cell Label okay_here; @@ -7029,7 +7041,7 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) { __ b(eq, &okay_here); __ ldr(r3, FieldMemOperand(r2, 0)); __ cmp(r3, Operand(cell_map)); - __ Assert(eq, kExpectedPropertyCellInRegisterEbx); + __ Assert(eq, "Expected property cell in register ebx"); __ bind(&okay_here); } @@ -7132,9 +7144,9 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { __ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); // Will both indicate a NULL and a Smi. __ tst(r3, Operand(kSmiTagMask)); - __ Assert(ne, kUnexpectedInitialMapForArrayFunction); + __ Assert(ne, "Unexpected initial map for Array function"); __ CompareObjectType(r3, r3, r4, MAP_TYPE); - __ Assert(eq, kUnexpectedInitialMapForArrayFunction); + __ Assert(eq, "Unexpected initial map for Array function"); } // Figure out the right elements kind @@ -7151,7 +7163,7 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { __ b(eq, &done); __ cmp(r3, Operand(FAST_HOLEY_ELEMENTS)); __ Assert(eq, - kInvalidElementsKindForInternalArrayOrInternalPackedArray); + "Invalid ElementsKind for InternalArray or InternalPackedArray"); __ bind(&done); } diff --git a/chromium/v8/src/arm/codegen-arm.cc b/chromium/v8/src/arm/codegen-arm.cc index 1bcf3e3a605..7559373ee9a 100644 --- a/chromium/v8/src/arm/codegen-arm.cc +++ b/chromium/v8/src/arm/codegen-arm.cc @@ -532,7 +532,7 @@ void ElementsTransitionGenerator::GenerateSmiToDouble( __ SmiTag(r9); __ orr(r9, r9, Operand(1)); __ CompareRoot(r9, Heap::kTheHoleValueRootIndex); - __ Assert(eq, kObjectFoundInSmiOnlyArray); + __ Assert(eq, "object found in smi-only array"); } __ Strd(r4, r5, MemOperand(r7, 8, PostIndex)); @@ -728,7 +728,7 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm, // Assert that we do not have a cons or slice (indirect strings) here. // Sequential strings have already been ruled out. __ tst(result, Operand(kIsIndirectStringMask)); - __ Assert(eq, kExternalStringExpectedButNotFound); + __ Assert(eq, "external string expected, but not found"); } // Rule out short external strings. STATIC_CHECK(kShortExternalStringTag != 0); diff --git a/chromium/v8/src/arm/debug-arm.cc b/chromium/v8/src/arm/debug-arm.cc index 108435f0a9f..7faea08034b 100644 --- a/chromium/v8/src/arm/debug-arm.cc +++ b/chromium/v8/src/arm/debug-arm.cc @@ -130,7 +130,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, if ((non_object_regs & (1 << r)) != 0) { if (FLAG_debug_code) { __ tst(reg, Operand(0xc0000000)); - __ Assert(eq, kUnableToEncodeValueAsSmi); + __ Assert(eq, "Unable to encode value as smi"); } __ SmiTag(reg); } @@ -313,12 +313,12 @@ void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) { void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { - masm->Abort(kLiveEditFrameDroppingIsNotSupportedOnArm); + masm->Abort("LiveEdit frame dropping is not supported on arm"); } void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { - masm->Abort(kLiveEditFrameDroppingIsNotSupportedOnArm); + masm->Abort("LiveEdit frame dropping is not supported on arm"); } const bool Debug::kFrameDropperSupported = false; diff --git a/chromium/v8/src/arm/full-codegen-arm.cc b/chromium/v8/src/arm/full-codegen-arm.cc index b73006a17d9..ea7b73f2fe9 100644 --- a/chromium/v8/src/arm/full-codegen-arm.cc +++ b/chromium/v8/src/arm/full-codegen-arm.cc @@ -786,9 +786,9 @@ void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { // Check that we're not inside a with or catch context. __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset)); __ CompareRoot(r1, Heap::kWithContextMapRootIndex); - __ Check(ne, kDeclarationInWithContext); + __ Check(ne, "Declaration in with context."); __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); - __ Check(ne, kDeclarationInCatchContext); + __ Check(ne, "Declaration in catch context."); } } @@ -2512,7 +2512,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, // Check for an uninitialized let binding. __ ldr(r2, location); __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); - __ Check(eq, kLetBindingReInitialization); + __ Check(eq, "Let binding re-initialization."); } // Perform the assignment. __ str(r0, location); @@ -3473,23 +3473,23 @@ void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string, Register value, uint32_t encoding_mask) { __ SmiTst(index); - __ Check(eq, kNonSmiIndex); + __ Check(eq, "Non-smi index"); __ SmiTst(value); - __ Check(eq, kNonSmiValue); + __ Check(eq, "Non-smi value"); __ ldr(ip, FieldMemOperand(string, String::kLengthOffset)); __ cmp(index, ip); - __ Check(lt, kIndexIsTooLarge); + __ Check(lt, "Index is too large"); __ cmp(index, Operand(Smi::FromInt(0))); - __ Check(ge, kIndexIsNegative); + __ Check(ge, "Index is negative"); __ ldr(ip, FieldMemOperand(string, HeapObject::kMapOffset)); __ ldrb(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset)); __ and_(ip, ip, Operand(kStringRepresentationMask | kStringEncodingMask)); __ cmp(ip, Operand(encoding_mask)); - __ Check(eq, kUnexpectedStringType); + __ Check(eq, "Unexpected string type"); } @@ -3849,7 +3849,7 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { Handle<FixedArray> jsfunction_result_caches( isolate()->native_context()->jsfunction_result_caches()); if (jsfunction_result_caches->length() <= cache_id) { - __ Abort(kAttemptToUseUndefinedCache); + __ Abort("Attempt to use undefined cache."); __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); context()->Plug(r0); return; @@ -4030,7 +4030,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // elements_end: Array end. if (generate_debug_code_) { __ cmp(array_length, Operand::Zero()); - __ Assert(gt, kNoEmptyArraysHereInEmitFastAsciiArrayJoin); + __ Assert(gt, "No empty arrays here in EmitFastAsciiArrayJoin"); } __ bind(&loop); __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); @@ -4349,12 +4349,35 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { break; } + case Token::SUB: + EmitUnaryOperation(expr, "[ UnaryOperation (SUB)"); + break; + + case Token::BIT_NOT: + EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)"); + break; + default: UNREACHABLE(); } } +void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr, + const char* comment) { + // TODO(svenpanne): Allowing format strings in Comment would be nice here... + Comment cmt(masm_, comment); + UnaryOpStub stub(expr->op()); + // UnaryOpStub expects the argument to be in the + // accumulator register r0. + VisitForAccumulatorValue(expr->expression()); + SetSourcePosition(expr->position()); + CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, + expr->UnaryOperationFeedbackId()); + context()->Plug(r0); +} + + void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { Comment cmnt(masm_, "[ CountOperation"); SetSourcePosition(expr->position()); diff --git a/chromium/v8/src/arm/lithium-arm.cc b/chromium/v8/src/arm/lithium-arm.cc index 998b73b62e9..e9ae04a1ee8 100644 --- a/chromium/v8/src/arm/lithium-arm.cc +++ b/chromium/v8/src/arm/lithium-arm.cc @@ -437,7 +437,7 @@ LPlatformChunk* LChunkBuilder::Build() { } -void LChunkBuilder::Abort(BailoutReason reason) { +void LChunkBuilder::Abort(const char* reason) { info()->set_bailout_reason(reason); status_ = ABORTED; } @@ -593,10 +593,8 @@ LInstruction* LChunkBuilder::DefineFixedDouble( LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) { HEnvironment* hydrogen_env = current_block_->last_environment(); int argument_index_accumulator = 0; - ZoneList<HValue*> objects_to_materialize(0, zone()); instr->set_environment(CreateEnvironment(hydrogen_env, - &argument_index_accumulator, - &objects_to_materialize)); + &argument_index_accumulator)); return instr; } @@ -647,7 +645,7 @@ LUnallocated* LChunkBuilder::TempRegister() { new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER); int vreg = allocator_->GetVirtualRegister(); if (!allocator_->AllocationOk()) { - Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister); + Abort("Out of virtual registers while trying to allocate temp register."); vreg = 0; } operand->set_virtual_register(vreg); @@ -885,7 +883,6 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { } #endif - instr->set_position(position_); if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) { instr = AssignPointerMap(instr); } @@ -901,13 +898,11 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { LEnvironment* LChunkBuilder::CreateEnvironment( HEnvironment* hydrogen_env, - int* argument_index_accumulator, - ZoneList<HValue*>* objects_to_materialize) { + int* argument_index_accumulator) { if (hydrogen_env == NULL) return NULL; - LEnvironment* outer = CreateEnvironment(hydrogen_env->outer(), - argument_index_accumulator, - objects_to_materialize); + LEnvironment* outer = + CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator); BailoutId ast_id = hydrogen_env->ast_id(); ASSERT(!ast_id.IsNone() || hydrogen_env->frame_type() != JS_FUNCTION); @@ -922,16 +917,16 @@ LEnvironment* LChunkBuilder::CreateEnvironment( outer, hydrogen_env->entry(), zone()); + bool needs_arguments_object_materialization = false; int argument_index = *argument_index_accumulator; - int object_index = objects_to_materialize->length(); for (int i = 0; i < hydrogen_env->length(); ++i) { if (hydrogen_env->is_special_index(i)) continue; - LOperand* op; HValue* value = hydrogen_env->values()->at(i); - if (value->IsArgumentsObject() || value->IsCapturedObject()) { - objects_to_materialize->Add(value, zone()); - op = LEnvironment::materialization_marker(); + LOperand* op = NULL; + if (value->IsArgumentsObject()) { + needs_arguments_object_materialization = true; + op = NULL; } else if (value->IsPushArgument()) { op = new(zone()) LArgument(argument_index++); } else { @@ -942,33 +937,15 @@ LEnvironment* LChunkBuilder::CreateEnvironment( value->CheckFlag(HInstruction::kUint32)); } - for (int i = object_index; i < objects_to_materialize->length(); ++i) { - HValue* object_to_materialize = objects_to_materialize->at(i); - int previously_materialized_object = -1; - for (int prev = 0; prev < i; ++prev) { - if (objects_to_materialize->at(prev) == objects_to_materialize->at(i)) { - previously_materialized_object = prev; - break; - } - } - int length = object_to_materialize->OperandCount(); - bool is_arguments = object_to_materialize->IsArgumentsObject(); - if (previously_materialized_object >= 0) { - result->AddDuplicateObject(previously_materialized_object); - continue; - } else { - result->AddNewObject(is_arguments ? length - 1 : length, is_arguments); - } - for (int i = is_arguments ? 1 : 0; i < length; ++i) { - LOperand* op; - HValue* value = object_to_materialize->OperandAt(i); - if (value->IsArgumentsObject() || value->IsCapturedObject()) { - objects_to_materialize->Add(value, zone()); - op = LEnvironment::materialization_marker(); - } else { - ASSERT(!value->IsPushArgument()); - op = UseAny(value); - } + if (needs_arguments_object_materialization) { + HArgumentsObject* arguments = hydrogen_env->entry() == NULL + ? graph()->GetArgumentsObject() + : hydrogen_env->entry()->arguments_object(); + ASSERT(arguments->IsLinked()); + for (int i = 1; i < arguments->arguments_count(); ++i) { + HValue* value = arguments->arguments_values()->at(i); + ASSERT(!value->IsArgumentsObject() && !value->IsPushArgument()); + LOperand* op = UseAny(value); result->AddValue(op, value->representation(), value->CheckFlag(HInstruction::kUint32)); @@ -1348,6 +1325,15 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { } +LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) { + ASSERT(instr->value()->representation().IsInteger32()); + ASSERT(instr->representation().IsInteger32()); + if (instr->HasNoUses()) return NULL; + LOperand* value = UseRegisterAtStart(instr->value()); + return DefineAsRegister(new(zone()) LBitNotI(value)); +} + + LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { if (instr->representation().IsDouble()) { return DoArithmeticD(Token::DIV, instr); @@ -1709,8 +1695,9 @@ LInstruction* LChunkBuilder::DoCompareNumericAndBranch( HCompareNumericAndBranch* instr) { Representation r = instr->representation(); if (r.IsSmiOrInteger32()) { - ASSERT(instr->left()->representation().Equals(r)); - ASSERT(instr->right()->representation().Equals(r)); + ASSERT(instr->left()->representation().IsSmiOrInteger32()); + ASSERT(instr->left()->representation().Equals( + instr->right()->representation())); LOperand* left = UseRegisterOrConstantAtStart(instr->left()); LOperand* right = UseRegisterOrConstantAtStart(instr->right()); return new(zone()) LCompareNumericAndBranch(left, right); @@ -1733,13 +1720,6 @@ LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch( } -LInstruction* LChunkBuilder::DoCompareHoleAndBranch( - HCompareHoleAndBranch* instr) { - LOperand* object = UseRegisterAtStart(instr->object()); - return new(zone()) LCmpHoleAndBranch(object); -} - - LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) { ASSERT(instr->value()->representation().IsTagged()); LOperand* value = UseRegisterAtStart(instr->value()); @@ -1852,6 +1832,17 @@ LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) { } +LInstruction* LChunkBuilder::DoNumericConstraint(HNumericConstraint* instr) { + return NULL; +} + + +LInstruction* LChunkBuilder::DoInductionVariableAnnotation( + HInductionVariableAnnotation* instr) { + return NULL; +} + + LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { LOperand* value = UseRegisterOrConstantAtStart(instr->index()); LOperand* length = UseRegister(instr->length()); @@ -2025,6 +2016,19 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { } +LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) { + LUnallocated* temp1 = NULL; + LOperand* temp2 = NULL; + if (!instr->CanOmitPrototypeChecks()) { + temp1 = TempRegister(); + temp2 = TempRegister(); + } + LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp1, temp2); + if (instr->CanOmitPrototypeChecks()) return result; + return AssignEnvironment(result); +} + + LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { LOperand* value = UseRegisterAtStart(instr->value()); return AssignEnvironment(new(zone()) LCheckFunction(value)); @@ -2033,16 +2037,10 @@ LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) { LOperand* value = NULL; - if (!instr->CanOmitMapChecks()) { - value = UseRegisterAtStart(instr->value()); - if (instr->has_migration_target()) info()->MarkAsDeferredCalling(); - } - LCheckMaps* result = new(zone()) LCheckMaps(value); - if (!instr->CanOmitMapChecks()) { - AssignEnvironment(result); - if (instr->has_migration_target()) return AssignPointerMap(result); - } - return result; + if (!instr->CanOmitMapChecks()) value = UseRegisterAtStart(instr->value()); + LInstruction* result = new(zone()) LCheckMaps(value); + if (instr->CanOmitMapChecks()) return result; + return AssignEnvironment(result); } @@ -2153,6 +2151,23 @@ LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) { } +LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic( + HLoadNamedFieldPolymorphic* instr) { + ASSERT(instr->representation().IsTagged()); + if (instr->need_generic()) { + LOperand* obj = UseFixed(instr->object(), r0); + LLoadNamedFieldPolymorphic* result = + new(zone()) LLoadNamedFieldPolymorphic(obj); + return MarkAsCall(DefineFixed(result, r0), instr); + } else { + LOperand* obj = UseRegisterAtStart(instr->object()); + LLoadNamedFieldPolymorphic* result = + new(zone()) LLoadNamedFieldPolymorphic(obj); + return AssignEnvironment(DefineAsRegister(result)); + } +} + + LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { LOperand* object = UseFixed(instr->object(), r0); LInstruction* result = DefineFixed(new(zone()) LLoadNamedGeneric(object), r0); @@ -2307,7 +2322,7 @@ LInstruction* LChunkBuilder::DoTrapAllocationMemento( LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) { bool is_in_object = instr->access().IsInobject(); bool needs_write_barrier = instr->NeedsWriteBarrier(); - bool needs_write_barrier_for_map = instr->has_transition() && + bool needs_write_barrier_for_map = !instr->transition().is_null() && instr->NeedsWriteBarrierForMap(); LOperand* obj; @@ -2427,7 +2442,7 @@ LInstruction* LChunkBuilder::DoParameter(HParameter* instr) { LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) { int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width. if (spill_index > LUnallocated::kMaxFixedSlotIndex) { - Abort(kTooManySpillSlotsNeededForOSR); + Abort("Too many spill slots needed for OSR"); spill_index = 0; } return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index); @@ -2449,12 +2464,6 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) { } -LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) { - // There are no real uses of a captured object. - return NULL; -} - - LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) { info()->MarkAsRequiresFrame(); LOperand* args = UseRegister(instr->arguments()); diff --git a/chromium/v8/src/arm/lithium-arm.h b/chromium/v8/src/arm/lithium-arm.h index d81dc0f57cd..c568ad6f95e 100644 --- a/chromium/v8/src/arm/lithium-arm.h +++ b/chromium/v8/src/arm/lithium-arm.h @@ -50,6 +50,7 @@ class LCodeGen; V(ArithmeticD) \ V(ArithmeticT) \ V(BitI) \ + V(BitNotI) \ V(BoundsCheck) \ V(Branch) \ V(CallConstantFunction) \ @@ -67,6 +68,7 @@ class LCodeGen; V(CheckNonSmi) \ V(CheckMaps) \ V(CheckMapValue) \ + V(CheckPrototypeMaps) \ V(CheckSmi) \ V(ClampDToUint8) \ V(ClampIToUint8) \ @@ -74,7 +76,6 @@ class LCodeGen; V(ClassOfTestAndBranch) \ V(CompareNumericAndBranch) \ V(CmpObjectEqAndBranch) \ - V(CmpHoleAndBranch) \ V(CmpMapAndBranch) \ V(CmpT) \ V(ConstantD) \ @@ -127,6 +128,7 @@ class LCodeGen; V(LoadKeyed) \ V(LoadKeyedGeneric) \ V(LoadNamedField) \ + V(LoadNamedFieldPolymorphic) \ V(LoadNamedGeneric) \ V(MapEnumLength) \ V(MathAbs) \ @@ -208,12 +210,9 @@ class LCodeGen; class LInstruction: public ZoneObject { public: LInstruction() - : environment_(NULL), - hydrogen_value_(NULL), - bit_field_(IsCallBits::encode(false)) { - set_position(RelocInfo::kNoPosition); - } - + : environment_(NULL), + hydrogen_value_(NULL), + is_call_(false) { } virtual ~LInstruction() { } virtual void CompileToNative(LCodeGen* generator) = 0; @@ -252,30 +251,20 @@ class LInstruction: public ZoneObject { LPointerMap* pointer_map() const { return pointer_map_.get(); } bool HasPointerMap() const { return pointer_map_.is_set(); } - // The 31 bits PositionBits is used to store the int position value. And the - // position value may be RelocInfo::kNoPosition (-1). The accessor always - // +1/-1 so that the encoded value of position in bit_field_ is always >= 0 - // and can fit into the 31 bits PositionBits. - void set_position(int pos) { - bit_field_ = PositionBits::update(bit_field_, pos + 1); - } - int position() { return PositionBits::decode(bit_field_) - 1; } - void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; } HValue* hydrogen_value() const { return hydrogen_value_; } virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { } - void MarkAsCall() { bit_field_ = IsCallBits::update(bit_field_, true); } - bool IsCall() const { return IsCallBits::decode(bit_field_); } + void MarkAsCall() { is_call_ = true; } // Interface to the register allocator and iterators. - bool ClobbersTemps() const { return IsCall(); } - bool ClobbersRegisters() const { return IsCall(); } - bool ClobbersDoubleRegisters() const { return IsCall(); } + bool ClobbersTemps() const { return is_call_; } + bool ClobbersRegisters() const { return is_call_; } + bool ClobbersDoubleRegisters() const { return is_call_; } // Interface to the register allocator and iterators. - bool IsMarkedAsCall() const { return IsCall(); } + bool IsMarkedAsCall() const { return is_call_; } virtual bool HasResult() const = 0; virtual LOperand* result() const = 0; @@ -299,13 +288,10 @@ class LInstruction: public ZoneObject { virtual int TempCount() = 0; virtual LOperand* TempAt(int i) = 0; - class IsCallBits: public BitField<bool, 0, 1> {}; - class PositionBits: public BitField<int, 1, 31> {}; - LEnvironment* environment_; SetOncePointer<LPointerMap> pointer_map_; HValue* hydrogen_value_; - int bit_field_; + bool is_call_; }; @@ -895,24 +881,12 @@ class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> { LOperand* left() { return inputs_[0]; } LOperand* right() { return inputs_[1]; } - DECLARE_CONCRETE_INSTRUCTION(CmpObjectEqAndBranch, "cmp-object-eq-and-branch") + DECLARE_CONCRETE_INSTRUCTION(CmpObjectEqAndBranch, + "cmp-object-eq-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareObjectEqAndBranch) }; -class LCmpHoleAndBranch: public LControlInstruction<1, 0> { - public: - explicit LCmpHoleAndBranch(LOperand* object) { - inputs_[0] = object; - } - - LOperand* object() { return inputs_[0]; } - - DECLARE_CONCRETE_INSTRUCTION(CmpHoleAndBranch, "cmp-hole-and-branch") - DECLARE_HYDROGEN_ACCESSOR(CompareHoleAndBranch) -}; - - class LIsObjectAndBranch: public LControlInstruction<1, 1> { public: LIsObjectAndBranch(LOperand* value, LOperand* temp) { @@ -1404,6 +1378,18 @@ class LThrow: public LTemplateInstruction<0, 1, 0> { }; +class LBitNotI: public LTemplateInstruction<1, 1, 0> { + public: + explicit LBitNotI(LOperand* value) { + inputs_[0] = value; + } + + LOperand* value() { return inputs_[0]; } + + DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i") +}; + + class LAddI: public LTemplateInstruction<1, 2, 0> { public: LAddI(LOperand* left, LOperand* right) { @@ -1539,6 +1525,19 @@ class LLoadNamedField: public LTemplateInstruction<1, 1, 0> { }; +class LLoadNamedFieldPolymorphic: public LTemplateInstruction<1, 1, 0> { + public: + explicit LLoadNamedFieldPolymorphic(LOperand* object) { + inputs_[0] = object; + } + + LOperand* object() { return inputs_[0]; } + + DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field-polymorphic") + DECLARE_HYDROGEN_ACCESSOR(LoadNamedFieldPolymorphic) +}; + + class LLoadNamedGeneric: public LTemplateInstruction<1, 1, 0> { public: explicit LLoadNamedGeneric(LOperand* object) { @@ -2151,7 +2150,7 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 1> { virtual void PrintDataTo(StringStream* stream); - Handle<Map> transition() const { return hydrogen()->transition_map(); } + Handle<Map> transition() const { return hydrogen()->transition(); } Representation representation() const { return hydrogen()->field_representation(); } @@ -2353,6 +2352,26 @@ class LCheckMaps: public LTemplateInstruction<0, 1, 0> { }; +class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 2> { + public: + LCheckPrototypeMaps(LOperand* temp, LOperand* temp2) { + temps_[0] = temp; + temps_[1] = temp2; + } + + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps") + DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps) + + ZoneList<Handle<JSObject> >* prototypes() const { + return hydrogen()->prototypes(); + } + ZoneList<Handle<Map> >* maps() const { return hydrogen()->maps(); } +}; + + class LCheckSmi: public LTemplateInstruction<1, 1, 0> { public: explicit LCheckSmi(LOperand* value) { @@ -2651,7 +2670,7 @@ class LChunkBuilder BASE_EMBEDDED { bool is_done() const { return status_ == DONE; } bool is_aborted() const { return status_ == ABORTED; } - void Abort(BailoutReason reason); + void Abort(const char* reason); // Methods for getting operands for Use / Define / Temp. LUnallocated* ToUnallocated(Register reg); @@ -2733,8 +2752,7 @@ class LChunkBuilder BASE_EMBEDDED { CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY); LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, - int* argument_index_accumulator, - ZoneList<HValue*>* objects_to_materialize); + int* argument_index_accumulator); void VisitInstruction(HInstruction* current); diff --git a/chromium/v8/src/arm/lithium-codegen-arm.cc b/chromium/v8/src/arm/lithium-codegen-arm.cc index 9ec80f819a0..cf1e7c70f5f 100644 --- a/chromium/v8/src/arm/lithium-codegen-arm.cc +++ b/chromium/v8/src/arm/lithium-codegen-arm.cc @@ -91,7 +91,7 @@ void LCodeGen::FinishCode(Handle<Code> code) { } -void LCodeGen::Abort(BailoutReason reason) { +void LCodeGen::Abort(const char* reason) { info()->set_bailout_reason(reason); status_ = ABORTED; } @@ -274,8 +274,6 @@ bool LCodeGen::GenerateBody() { instr->Mnemonic()); } - RecordAndUpdatePosition(instr->position()); - instr->CompileToNative(this); } EnsureSpaceForLazyDeopt(); @@ -289,10 +287,6 @@ bool LCodeGen::GenerateDeferredCode() { if (deferred_.length() > 0) { for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { LDeferredCode* code = deferred_[i]; - - int pos = instructions_->at(code->instruction_index())->position(); - RecordAndUpdatePosition(pos); - Comment(";;; <@%d,#%d> " "-------------------- Deferred %s --------------------", code->instruction_index(), @@ -340,7 +334,7 @@ bool LCodeGen::GenerateDeoptJumpTable() { // 32bit data after it. if (!is_int24((masm()->pc_offset() / Assembler::kInstrSize) + deopt_jump_table_.length() * 7)) { - Abort(kGeneratedCodeIsTooLarge); + Abort("Generated code is too large"); } if (deopt_jump_table_.length() > 0) { @@ -429,7 +423,7 @@ Register LCodeGen::EmitLoadRegister(LOperand* op, Register scratch) { ASSERT(literal->IsNumber()); __ mov(scratch, Operand(static_cast<int32_t>(literal->Number()))); } else if (r.IsDouble()) { - Abort(kEmitLoadRegisterUnsupportedDoubleImmediate); + Abort("EmitLoadRegister: Unsupported double immediate."); } else { ASSERT(r.IsTagged()); __ LoadObject(scratch, literal); @@ -467,9 +461,9 @@ DwVfpRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op, __ vcvt_f64_s32(dbl_scratch, flt_scratch); return dbl_scratch; } else if (r.IsDouble()) { - Abort(kUnsupportedDoubleImmediate); + Abort("unsupported double immediate"); } else if (r.IsTagged()) { - Abort(kUnsupportedTaggedImmediate); + Abort("unsupported tagged immediate"); } } else if (op->IsStackSlot() || op->IsArgument()) { // TODO(regis): Why is vldr not taking a MemOperand? @@ -540,14 +534,14 @@ Operand LCodeGen::ToOperand(LOperand* op) { ASSERT(constant->HasInteger32Value()); return Operand(constant->Integer32Value()); } else if (r.IsDouble()) { - Abort(kToOperandUnsupportedDoubleImmediate); + Abort("ToOperand Unsupported double immediate."); } ASSERT(r.IsTagged()); return Operand(constant->handle()); } else if (op->IsRegister()) { return Operand(ToRegister(op)); } else if (op->IsDoubleRegister()) { - Abort(kToOperandIsDoubleRegisterUnimplemented); + Abort("ToOperand IsDoubleRegister unimplemented"); return Operand::Zero(); } // Stack slots not implemented, use ToMemOperand instead. @@ -611,57 +605,37 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, break; } - int object_index = 0; - int dematerialized_index = 0; for (int i = 0; i < translation_size; ++i) { LOperand* value = environment->values()->at(i); - AddToTranslation(environment, - translation, + + // TODO(mstarzinger): Introduce marker operands to indicate that this value + // is not present and must be reconstructed from the deoptimizer. Currently + // this is only used for the arguments object. + if (value == NULL) { + int arguments_count = environment->values()->length() - translation_size; + translation->BeginArgumentsObject(arguments_count); + for (int i = 0; i < arguments_count; ++i) { + LOperand* value = environment->values()->at(translation_size + i); + AddToTranslation(translation, + value, + environment->HasTaggedValueAt(translation_size + i), + environment->HasUint32ValueAt(translation_size + i)); + } + continue; + } + + AddToTranslation(translation, value, environment->HasTaggedValueAt(i), - environment->HasUint32ValueAt(i), - &object_index, - &dematerialized_index); + environment->HasUint32ValueAt(i)); } } -void LCodeGen::AddToTranslation(LEnvironment* environment, - Translation* translation, +void LCodeGen::AddToTranslation(Translation* translation, LOperand* op, bool is_tagged, - bool is_uint32, - int* object_index_pointer, - int* dematerialized_index_pointer) { - if (op == LEnvironment::materialization_marker()) { - int object_index = (*object_index_pointer)++; - if (environment->ObjectIsDuplicateAt(object_index)) { - int dupe_of = environment->ObjectDuplicateOfAt(object_index); - translation->DuplicateObject(dupe_of); - return; - } - int object_length = environment->ObjectLengthAt(object_index); - if (environment->ObjectIsArgumentsAt(object_index)) { - translation->BeginArgumentsObject(object_length); - } else { - translation->BeginCapturedObject(object_length); - } - int dematerialized_index = *dematerialized_index_pointer; - int env_offset = environment->translation_size() + dematerialized_index; - *dematerialized_index_pointer += object_length; - for (int i = 0; i < object_length; ++i) { - LOperand* value = environment->values()->at(env_offset + i); - AddToTranslation(environment, - translation, - value, - environment->HasTaggedValueAt(env_offset + i), - environment->HasUint32ValueAt(env_offset + i), - object_index_pointer, - dematerialized_index_pointer); - } - return; - } - + bool is_uint32) { if (op->IsStackSlot()) { if (is_tagged) { translation->StoreStackSlot(op->index()); @@ -788,7 +762,7 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment, } -void LCodeGen::DeoptimizeIf(Condition condition, +void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment, Deoptimizer::BailoutType bailout_type) { RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); @@ -798,7 +772,7 @@ void LCodeGen::DeoptimizeIf(Condition condition, Address entry = Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type); if (entry == NULL) { - Abort(kBailoutWasNotPrepared); + Abort("bailout was not prepared"); return; } @@ -811,12 +785,12 @@ void LCodeGen::DeoptimizeIf(Condition condition, return; } - if (info()->ShouldTrapOnDeopt()) { - __ stop("trap_on_deopt", condition); + if (FLAG_trap_on_deopt && info()->IsOptimizing()) { + __ stop("trap_on_deopt", cc); } ASSERT(info()->IsStub() || frame_is_built_); - if (condition == al && frame_is_built_) { + if (cc == al && frame_is_built_) { __ Call(entry, RelocInfo::RUNTIME_ENTRY); } else { // We often have several deopts to the same entry, reuse the last @@ -830,17 +804,17 @@ void LCodeGen::DeoptimizeIf(Condition condition, !frame_is_built_); deopt_jump_table_.Add(table_entry, zone()); } - __ b(condition, &deopt_jump_table_.last().label); + __ b(cc, &deopt_jump_table_.last().label); } } -void LCodeGen::DeoptimizeIf(Condition condition, +void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { Deoptimizer::BailoutType bailout_type = info()->IsStub() ? Deoptimizer::LAZY : Deoptimizer::EAGER; - DeoptimizeIf(condition, environment, bailout_type); + DeoptimizeIf(cc, environment, bailout_type); } @@ -1003,14 +977,6 @@ void LCodeGen::RecordPosition(int position) { } -void LCodeGen::RecordAndUpdatePosition(int position) { - if (position >= 0 && position != old_position_) { - masm()->positions_recorder()->RecordPosition(position); - old_position_ = position; - } -} - - static const char* LabelType(LLabel* label) { if (label->is_loop_header()) return " (loop header)"; if (label->is_osr_entry()) return " (OSR entry)"; @@ -1703,11 +1669,7 @@ void LCodeGen::DoBitI(LBitI* instr) { __ orr(result, left, right); break; case Token::BIT_XOR: - if (right_op->IsConstantOperand() && right.immediate() == int32_t(~0)) { - __ mvn(result, Operand(left)); - } else { - __ eor(result, left, right); - } + __ eor(result, left, right); break; default: UNREACHABLE(); @@ -1974,7 +1936,7 @@ void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; __ cmp(ip, Operand(encoding == String::ONE_BYTE_ENCODING ? one_byte_seq_type : two_byte_seq_type)); - __ Check(eq, kUnexpectedStringType); + __ Check(eq, "Unexpected string type"); } __ add(ip, @@ -1991,6 +1953,13 @@ void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { } +void LCodeGen::DoBitNotI(LBitNotI* instr) { + Register input = ToRegister(instr->value()); + Register result = ToRegister(instr->result()); + __ mvn(result, Operand(input)); +} + + void LCodeGen::DoThrow(LThrow* instr) { Register input_reg = EmitLoadRegister(instr->value(), ip); __ push(input_reg); @@ -2152,32 +2121,25 @@ int LCodeGen::GetNextEmittedBlock() const { } template<class InstrType> -void LCodeGen::EmitBranch(InstrType instr, Condition condition) { +void LCodeGen::EmitBranch(InstrType instr, Condition cc) { int left_block = instr->TrueDestination(chunk_); int right_block = instr->FalseDestination(chunk_); int next_block = GetNextEmittedBlock(); - if (right_block == left_block || condition == al) { + if (right_block == left_block || cc == al) { EmitGoto(left_block); } else if (left_block == next_block) { - __ b(NegateCondition(condition), chunk_->GetAssemblyLabel(right_block)); + __ b(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block)); } else if (right_block == next_block) { - __ b(condition, chunk_->GetAssemblyLabel(left_block)); + __ b(cc, chunk_->GetAssemblyLabel(left_block)); } else { - __ b(condition, chunk_->GetAssemblyLabel(left_block)); + __ b(cc, chunk_->GetAssemblyLabel(left_block)); __ b(chunk_->GetAssemblyLabel(right_block)); } } -template<class InstrType> -void LCodeGen::EmitFalseBranch(InstrType instr, Condition condition) { - int false_block = instr->FalseDestination(chunk_); - __ b(condition, chunk_->GetAssemblyLabel(false_block)); -} - - void LCodeGen::DoDebugBreak(LDebugBreak* instr) { __ stop("LBreak"); } @@ -2433,26 +2395,6 @@ void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { } -void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) { - if (instr->hydrogen()->representation().IsTagged()) { - Register input_reg = ToRegister(instr->object()); - __ mov(ip, Operand(factory()->the_hole_value())); - __ cmp(input_reg, ip); - EmitBranch(instr, eq); - return; - } - - DwVfpRegister input_reg = ToDoubleRegister(instr->object()); - __ VFPCompareAndSetFlags(input_reg, input_reg); - EmitFalseBranch(instr, vc); - - Register scratch = scratch0(); - __ VmovHigh(scratch, input_reg); - __ cmp(scratch, Operand(kHoleNanUpper32)); - EmitBranch(instr, eq); -} - - Condition LCodeGen::EmitIsObject(Register input, Register temp1, Label* is_not_object, @@ -3079,6 +3021,91 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { } +void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, + Register object, + Handle<Map> type, + Handle<String> name, + LEnvironment* env) { + LookupResult lookup(isolate()); + type->LookupDescriptor(NULL, *name, &lookup); + ASSERT(lookup.IsFound() || lookup.IsCacheable()); + if (lookup.IsField()) { + int index = lookup.GetLocalFieldIndexFromMap(*type); + int offset = index * kPointerSize; + if (index < 0) { + // Negative property indices are in-object properties, indexed + // from the end of the fixed part of the object. + __ ldr(result, FieldMemOperand(object, offset + type->instance_size())); + } else { + // Non-negative property indices are in the properties array. + __ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); + __ ldr(result, FieldMemOperand(result, offset + FixedArray::kHeaderSize)); + } + } else if (lookup.IsConstant()) { + Handle<Object> constant(lookup.GetConstantFromMap(*type), isolate()); + __ LoadObject(result, constant); + } else { + // Negative lookup. + // Check prototypes. + Handle<HeapObject> current(HeapObject::cast((*type)->prototype())); + Heap* heap = type->GetHeap(); + while (*current != heap->null_value()) { + __ LoadHeapObject(result, current); + __ ldr(result, FieldMemOperand(result, HeapObject::kMapOffset)); + __ cmp(result, Operand(Handle<Map>(current->map()))); + DeoptimizeIf(ne, env); + current = + Handle<HeapObject>(HeapObject::cast(current->map()->prototype())); + } + __ LoadRoot(result, Heap::kUndefinedValueRootIndex); + } +} + + +void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) { + Register object = ToRegister(instr->object()); + Register result = ToRegister(instr->result()); + Register object_map = scratch0(); + + int map_count = instr->hydrogen()->types()->length(); + bool need_generic = instr->hydrogen()->need_generic(); + + if (map_count == 0 && !need_generic) { + DeoptimizeIf(al, instr->environment()); + return; + } + Handle<String> name = instr->hydrogen()->name(); + Label done; + __ ldr(object_map, FieldMemOperand(object, HeapObject::kMapOffset)); + for (int i = 0; i < map_count; ++i) { + bool last = (i == map_count - 1); + Handle<Map> map = instr->hydrogen()->types()->at(i); + Label check_passed; + __ CompareMap(object_map, map, &check_passed); + if (last && !need_generic) { + DeoptimizeIf(ne, instr->environment()); + __ bind(&check_passed); + EmitLoadFieldOrConstantFunction( + result, object, map, name, instr->environment()); + } else { + Label next; + __ b(ne, &next); + __ bind(&check_passed); + EmitLoadFieldOrConstantFunction( + result, object, map, name, instr->environment()); + __ b(&done); + __ bind(&next); + } + } + if (need_generic) { + __ mov(r2, Operand(name)); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); + CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); + } + __ bind(&done); +} + + void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { ASSERT(ToRegister(instr->object()).is(r0)); ASSERT(ToRegister(instr->result()).is(r0)); @@ -3173,7 +3200,7 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { if (key_is_constant) { constant_key = ToInteger32(LConstantOperand::cast(instr->key())); if (constant_key & 0xF0000000) { - Abort(kArrayIndexConstantValueTooBig); + Abort("array index constant value too big."); } } else { key = ToRegister(instr->key()); @@ -3257,7 +3284,7 @@ void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { if (key_is_constant) { constant_key = ToInteger32(LConstantOperand::cast(instr->key())); if (constant_key & 0xF0000000) { - Abort(kArrayIndexConstantValueTooBig); + Abort("array index constant value too big."); } } else { key = ToRegister(instr->key()); @@ -3518,7 +3545,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { void LCodeGen::DoPushArgument(LPushArgument* instr) { LOperand* argument = instr->value(); if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) { - Abort(kDoPushArgumentNotImplementedForDoubleType); + Abort("DoPushArgument not implemented for double type."); } else { Register argument_reg = EmitLoadRegister(argument, ip); __ push(argument_reg); @@ -3738,7 +3765,7 @@ void LCodeGen::DoMathAbs(LMathAbs* instr) { DwVfpRegister input = ToDoubleRegister(instr->value()); DwVfpRegister result = ToDoubleRegister(instr->result()); __ vabs(result, input); - } else if (r.IsSmiOrInteger32()) { + } else if (r.IsInteger32()) { EmitIntegerMathAbs(instr); } else { // Representation is tagged. @@ -4251,14 +4278,14 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { } -void LCodeGen::ApplyCheckIf(Condition condition, LBoundsCheck* check) { +void LCodeGen::ApplyCheckIf(Condition cc, LBoundsCheck* check) { if (FLAG_debug_code && check->hydrogen()->skip_check()) { Label done; - __ b(NegateCondition(condition), &done); + __ b(NegateCondition(cc), &done); __ stop("eliminated bounds check failed"); __ bind(&done); } else { - DeoptimizeIf(condition, check->environment()); + DeoptimizeIf(cc, check->environment()); } } @@ -4292,7 +4319,7 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { if (key_is_constant) { constant_key = ToInteger32(LConstantOperand::cast(instr->key())); if (constant_key & 0xF0000000) { - Abort(kArrayIndexConstantValueTooBig); + Abort("array index constant value too big."); } } else { key = ToRegister(instr->key()); @@ -4365,7 +4392,7 @@ void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { if (key_is_constant) { constant_key = ToInteger32(LConstantOperand::cast(instr->key())); if (constant_key & 0xF0000000) { - Abort(kArrayIndexConstantValueTooBig); + Abort("array index constant value too big."); } } else { key = ToRegister(instr->key()); @@ -4388,7 +4415,7 @@ void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { if (masm()->emit_debug_code()) { __ vmrs(ip); __ tst(ip, Operand(kVFPDefaultNaNModeControlBit)); - __ Assert(ne, kDefaultNaNModeNotSet); + __ Assert(ne, "Default NaN mode not set"); } __ VFPCanonicalizeNaN(value); } @@ -4489,13 +4516,12 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, scratch, GetLinkRegisterState(), kDontSaveFPRegs); } else { - PushSafepointRegistersScope scope( - this, Safepoint::kWithRegistersAndDoubles); + PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); __ Move(r0, object_reg); __ Move(r1, to_map); TransitionElementsKindStub stub(from_kind, to_kind); __ CallStub(&stub); - RecordSafepointWithRegistersAndDoubles( + RecordSafepointWithRegisters( instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); } __ bind(¬_applicable); @@ -4783,6 +4809,29 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { Register temp1 = ToRegister(instr->temp()); Register temp2 = ToRegister(instr->temp2()); + bool convert_hole = false; + HValue* change_input = instr->hydrogen()->value(); + if (change_input->IsLoadKeyed()) { + HLoadKeyed* load = HLoadKeyed::cast(change_input); + convert_hole = load->UsesMustHandleHole(); + } + + Label no_special_nan_handling; + Label done; + if (convert_hole) { + DwVfpRegister input_reg = ToDoubleRegister(instr->value()); + __ VFPCompareAndSetFlags(input_reg, input_reg); + __ b(vc, &no_special_nan_handling); + __ VmovHigh(scratch, input_reg); + __ cmp(scratch, Operand(kHoleNanUpper32)); + // If not the hole NaN, force the NaN to be canonical. + __ VFPCanonicalizeNaN(input_reg, ne); + __ b(ne, &no_special_nan_handling); + __ Move(reg, factory()->the_hole_value()); + __ b(&done); + } + + __ bind(&no_special_nan_handling); DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr); if (FLAG_inline_new) { __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex); @@ -4796,6 +4845,7 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { __ vstr(input_reg, reg, HeapNumber::kValueOffset); // Now that we have finished with the object's real address tag it __ add(reg, reg, Operand(kHeapObjectTag)); + __ bind(&done); } @@ -4835,7 +4885,7 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { void LCodeGen::EmitNumberUntagD(Register input_reg, DwVfpRegister result_reg, - bool can_convert_undefined_to_nan, + bool allow_undefined_as_nan, bool deoptimize_on_minus_zero, LEnvironment* env, NumberUntagDMode mode) { @@ -4845,7 +4895,9 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, Label load_smi, heap_number, done; - if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) { + STATIC_ASSERT(NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE > + NUMBER_CANDIDATE_IS_ANY_TAGGED); + if (mode >= NUMBER_CANDIDATE_IS_ANY_TAGGED) { // Smi check. __ UntagAndJumpIfSmi(scratch, input_reg, &load_smi); @@ -4853,7 +4905,7 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset)); __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); __ cmp(scratch, Operand(ip)); - if (!can_convert_undefined_to_nan) { + if (!allow_undefined_as_nan) { DeoptimizeIf(ne, env); } else { Label heap_number, convert; @@ -4862,6 +4914,11 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, // Convert undefined (and hole) to NaN. __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); __ cmp(input_reg, Operand(ip)); + if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE) { + __ b(eq, &convert); + __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); + __ cmp(input_reg, Operand(ip)); + } DeoptimizeIf(ne, env); __ bind(&convert); @@ -5002,12 +5059,21 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { Register input_reg = ToRegister(input); DwVfpRegister result_reg = ToDoubleRegister(result); + NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED; HValue* value = instr->hydrogen()->value(); - NumberUntagDMode mode = value->representation().IsSmi() - ? NUMBER_CANDIDATE_IS_SMI : NUMBER_CANDIDATE_IS_ANY_TAGGED; + if (value->type().IsSmi()) { + mode = NUMBER_CANDIDATE_IS_SMI; + } else if (value->IsLoadKeyed()) { + HLoadKeyed* load = HLoadKeyed::cast(value); + if (load->UsesMustHandleHole()) { + if (load->hole_mode() == ALLOW_RETURN_HOLE) { + mode = NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE; + } + } + } EmitNumberUntagD(input_reg, result_reg, - instr->hydrogen()->can_convert_undefined_to_nan(), + instr->hydrogen()->allow_undefined_as_nan(), instr->hydrogen()->deoptimize_on_minus_zero(), instr->environment(), mode); @@ -5137,7 +5203,7 @@ void LCodeGen::DoCheckFunction(LCheckFunction* instr) { AllowDeferredHandleDereference smi_check; if (isolate()->heap()->InNewSpace(*target)) { Register reg = ToRegister(instr->value()); - Handle<Cell> cell = isolate()->factory()->NewCell(target); + Handle<Cell> cell = isolate()->factory()->NewPropertyCell(target); __ mov(ip, Operand(Handle<Object>(cell))); __ ldr(ip, FieldMemOperand(ip, Cell::kValueOffset)); __ cmp(reg, ip); @@ -5148,67 +5214,33 @@ void LCodeGen::DoCheckFunction(LCheckFunction* instr) { } -void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) { - { - PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); - __ push(object); - CallRuntimeFromDeferred(Runtime::kMigrateInstance, 1, instr); - __ StoreToSafepointRegisterSlot(r0, scratch0()); - } - __ tst(scratch0(), Operand(kSmiTagMask)); - DeoptimizeIf(eq, instr->environment()); +void LCodeGen::DoCheckMapCommon(Register map_reg, + Handle<Map> map, + LEnvironment* env) { + Label success; + __ CompareMap(map_reg, map, &success); + DeoptimizeIf(ne, env); + __ bind(&success); } void LCodeGen::DoCheckMaps(LCheckMaps* instr) { - class DeferredCheckMaps: public LDeferredCode { - public: - DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object) - : LDeferredCode(codegen), instr_(instr), object_(object) { - SetExit(check_maps()); - } - virtual void Generate() { - codegen()->DoDeferredInstanceMigration(instr_, object_); - } - Label* check_maps() { return &check_maps_; } - virtual LInstruction* instr() { return instr_; } - private: - LCheckMaps* instr_; - Label check_maps_; - Register object_; - }; - if (instr->hydrogen()->CanOmitMapChecks()) return; Register map_reg = scratch0(); - LOperand* input = instr->value(); ASSERT(input->IsRegister()); Register reg = ToRegister(input); + Label success; SmallMapList* map_set = instr->hydrogen()->map_set(); __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); - - DeferredCheckMaps* deferred = NULL; - if (instr->hydrogen()->has_migration_target()) { - deferred = new(zone()) DeferredCheckMaps(this, instr, reg); - __ bind(deferred->check_maps()); - } - - Label success; for (int i = 0; i < map_set->length() - 1; i++) { Handle<Map> map = map_set->at(i); __ CompareMap(map_reg, map, &success); __ b(eq, &success); } - Handle<Map> map = map_set->last(); - __ CompareMap(map_reg, map, &success); - if (instr->hydrogen()->has_migration_target()) { - __ b(ne, deferred->entry()); - } else { - DeoptimizeIf(ne, instr->environment()); - } - + DoCheckMapCommon(map_reg, map, instr->environment()); __ bind(&success); } @@ -5263,6 +5295,25 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { } +void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { + if (instr->hydrogen()->CanOmitPrototypeChecks()) return; + + Register prototype_reg = ToRegister(instr->temp()); + Register map_reg = ToRegister(instr->temp2()); + + ZoneList<Handle<JSObject> >* prototypes = instr->prototypes(); + ZoneList<Handle<Map> >* maps = instr->maps(); + + ASSERT(prototypes->length() == maps->length()); + + for (int i = 0; i < prototypes->length(); i++) { + __ LoadHeapObject(prototype_reg, prototypes->at(i)); + __ ldr(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset)); + DoCheckMapCommon(map_reg, maps->at(i), instr->environment()); + } +} + + void LCodeGen::DoAllocate(LAllocate* instr) { class DeferredAllocate: public LDeferredCode { public: @@ -5597,8 +5648,6 @@ void LCodeGen::DoDeoptimize(LDeoptimize* instr) { if (info()->IsStub() && type == Deoptimizer::EAGER) { type = Deoptimizer::LAZY; } - - Comment(";;; deoptimize: %s", instr->hydrogen()->reason()); DeoptimizeIf(al, instr->environment(), type); } diff --git a/chromium/v8/src/arm/lithium-codegen-arm.h b/chromium/v8/src/arm/lithium-codegen-arm.h index d0bfcbbb94e..21f792153ba 100644 --- a/chromium/v8/src/arm/lithium-codegen-arm.h +++ b/chromium/v8/src/arm/lithium-codegen-arm.h @@ -66,8 +66,7 @@ class LCodeGen BASE_EMBEDDED { frame_is_built_(false), safepoints_(info->zone()), resolver_(this), - expected_safepoint_kind_(Safepoint::kSimple), - old_position_(RelocInfo::kNoPosition) { + expected_safepoint_kind_(Safepoint::kSimple) { PopulateDeoptimizationLiteralsWithInlinedFunctions(); } @@ -116,7 +115,7 @@ class LCodeGen BASE_EMBEDDED { DwVfpRegister EmitLoadDoubleRegister(LOperand* op, SwVfpRegister flt_scratch, DwVfpRegister dbl_scratch); - int32_t ToRepresentation(LConstantOperand* op, const Representation& r) const; + int ToRepresentation(LConstantOperand* op, const Representation& r) const; int32_t ToInteger32(LConstantOperand* op) const; Smi* ToSmi(LConstantOperand* op) const; double ToDouble(LConstantOperand* op) const; @@ -155,7 +154,8 @@ class LCodeGen BASE_EMBEDDED { void DoDeferredAllocate(LAllocate* instr); void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, Label* map_check); - void DoDeferredInstanceMigration(LCheckMaps* instr, Register object); + + void DoCheckMapCommon(Register map_reg, Handle<Map> map, LEnvironment* env); // Parallel move support. void DoParallelMove(LParallelMove* move); @@ -214,7 +214,7 @@ class LCodeGen BASE_EMBEDDED { int GetStackSlotCount() const { return chunk()->spill_slot_count(); } - void Abort(BailoutReason reason); + void Abort(const char* reason); void FPRINTF_CHECKING Comment(const char* format, ...); void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); } @@ -281,19 +281,16 @@ class LCodeGen BASE_EMBEDDED { void RegisterEnvironmentForDeoptimization(LEnvironment* environment, Safepoint::DeoptMode mode); - void DeoptimizeIf(Condition condition, + void DeoptimizeIf(Condition cc, LEnvironment* environment, Deoptimizer::BailoutType bailout_type); - void DeoptimizeIf(Condition condition, LEnvironment* environment); - void ApplyCheckIf(Condition condition, LBoundsCheck* check); + void DeoptimizeIf(Condition cc, LEnvironment* environment); + void ApplyCheckIf(Condition cc, LBoundsCheck* check); - void AddToTranslation(LEnvironment* environment, - Translation* translation, + void AddToTranslation(Translation* translation, LOperand* op, bool is_tagged, - bool is_uint32, - int* object_index_pointer, - int* dematerialized_index_pointer); + bool is_uint32); void RegisterDependentCodeForEmbeddedMaps(Handle<Code> code); void PopulateDeoptimizationData(Handle<Code> code); int DefineDeoptimizationLiteral(Handle<Object> literal); @@ -319,14 +316,11 @@ class LCodeGen BASE_EMBEDDED { int arguments, Safepoint::DeoptMode mode); void RecordPosition(int position); - void RecordAndUpdatePosition(int position); static Condition TokenToCondition(Token::Value op, bool is_unsigned); void EmitGoto(int block); template<class InstrType> - void EmitBranch(InstrType instr, Condition condition); - template<class InstrType> - void EmitFalseBranch(InstrType instr, Condition condition); + void EmitBranch(InstrType instr, Condition cc); void EmitNumberUntagD(Register input, DwVfpRegister result, bool allow_undefined_as_nan, @@ -362,6 +356,12 @@ class LCodeGen BASE_EMBEDDED { // Caller should branch on equal condition. void EmitIsConstructCall(Register temp1, Register temp2); + void EmitLoadFieldOrConstantFunction(Register result, + Register object, + Handle<Map> type, + Handle<String> name, + LEnvironment* env); + // Emits optimized code to deep-copy the contents of statically known // object graphs (e.g. object literal boilerplate). void EmitDeepCopy(Handle<JSObject> object, @@ -418,8 +418,6 @@ class LCodeGen BASE_EMBEDDED { Safepoint::Kind expected_safepoint_kind_; - int old_position_; - class PushSafepointRegistersScope BASE_EMBEDDED { public: PushSafepointRegistersScope(LCodeGen* codegen, diff --git a/chromium/v8/src/arm/lithium-gap-resolver-arm.cc b/chromium/v8/src/arm/lithium-gap-resolver-arm.cc index 88ac7a2a21d..7a3c96892c2 100644 --- a/chromium/v8/src/arm/lithium-gap-resolver-arm.cc +++ b/chromium/v8/src/arm/lithium-gap-resolver-arm.cc @@ -254,7 +254,7 @@ void LGapResolver::EmitMove(int index) { } else { __ LoadObject(dst, cgen_->ToHandle(constant_source)); } - } else if (destination->IsDoubleRegister()) { + } else if (source->IsDoubleRegister()) { DwVfpRegister result = cgen_->ToDoubleRegister(destination); double v = cgen_->ToDouble(constant_source); __ Vmov(result, v, ip); diff --git a/chromium/v8/src/arm/macro-assembler-arm.cc b/chromium/v8/src/arm/macro-assembler-arm.cc index a56744bf597..cd124610f97 100644 --- a/chromium/v8/src/arm/macro-assembler-arm.cc +++ b/chromium/v8/src/arm/macro-assembler-arm.cc @@ -375,13 +375,16 @@ void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index, Condition cond) { if (CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS) && - isolate()->heap()->RootCanBeTreatedAsConstant(index) && + !Heap::RootCanBeWrittenAfterInitialization(index) && !predictable_code_size()) { - // The CPU supports fast immediate values, and this root will never - // change. We will load it as a relocatable immediate value. - Handle<Object> root(&isolate()->heap()->roots_array_start()[index]); - mov(destination, Operand(root), LeaveCC, cond); - return; + Handle<Object> root(isolate()->heap()->roots_array_start()[index], + isolate()); + if (!isolate()->heap()->InNewSpace(*root)) { + // The CPU supports fast immediate values, and this root will never + // change. We will load it as a relocatable immediate value. + mov(destination, Operand(root), LeaveCC, cond); + return; + } } ldr(destination, MemOperand(kRootRegister, index << kPointerSizeLog2), cond); } @@ -486,7 +489,7 @@ void MacroAssembler::RecordWrite(Register object, if (emit_debug_code()) { ldr(ip, MemOperand(address)); cmp(ip, value); - Check(eq, kWrongAddressOrValuePassedToRecordWrite); + Check(eq, "Wrong address or value passed to RecordWrite"); } Label done; @@ -1487,7 +1490,7 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, // In debug mode, make sure the lexical context is set. #ifdef DEBUG cmp(scratch, Operand::Zero()); - Check(ne, kWeShouldNotHaveAnEmptyLexicalContext); + Check(ne, "we should not have an empty lexical context"); #endif // Load the native context of the current context. @@ -1505,7 +1508,7 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, ldr(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset)); LoadRoot(ip, Heap::kNativeContextMapRootIndex); cmp(holder_reg, ip); - Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext); + Check(eq, "JSGlobalObject::native_context should be a native context."); pop(holder_reg); // Restore holder. } @@ -1522,12 +1525,12 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, mov(holder_reg, ip); // Move ip to its holding place. LoadRoot(ip, Heap::kNullValueRootIndex); cmp(holder_reg, ip); - Check(ne, kJSGlobalProxyContextShouldNotBeNull); + Check(ne, "JSGlobalProxy::context() should not be null."); ldr(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset)); LoadRoot(ip, Heap::kNativeContextMapRootIndex); cmp(holder_reg, ip); - Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext); + Check(eq, "JSGlobalObject::native_context should be a native context."); // Restore ip is not needed. ip is reloaded below. pop(holder_reg); // Restore holder. // Restore ip to holder's context. @@ -1724,7 +1727,7 @@ void MacroAssembler::Allocate(int object_size, // respect to register content between debug and release mode. ldr(ip, MemOperand(topaddr)); cmp(result, ip); - Check(eq, kUnexpectedAllocationTop); + Check(eq, "Unexpected allocation top"); } // Load allocation limit into ip. Result already contains allocation top. ldr(ip, MemOperand(topaddr, limit - top)); @@ -1822,7 +1825,7 @@ void MacroAssembler::Allocate(Register object_size, // respect to register content between debug and release mode. ldr(ip, MemOperand(topaddr)); cmp(result, ip); - Check(eq, kUnexpectedAllocationTop); + Check(eq, "Unexpected allocation top"); } // Load allocation limit into ip. Result already contains allocation top. ldr(ip, MemOperand(topaddr, limit - top)); @@ -1856,7 +1859,7 @@ void MacroAssembler::Allocate(Register object_size, // Update allocation top. result temporarily holds the new top. if (emit_debug_code()) { tst(scratch2, Operand(kObjectAlignmentMask)); - Check(eq, kUnalignedAllocationInNewSpace); + Check(eq, "Unaligned allocation in new space"); } str(scratch2, MemOperand(topaddr)); @@ -1879,7 +1882,7 @@ void MacroAssembler::UndoAllocationInNewSpace(Register object, mov(scratch, Operand(new_space_allocation_top)); ldr(scratch, MemOperand(scratch)); cmp(object, scratch); - Check(lt, kUndoAllocationOfNonAllocatedMemory); + Check(lt, "Undo allocation of non allocated memory"); #endif // Write the address of the object to un-allocate as the current top. mov(scratch, Operand(new_space_allocation_top)); @@ -2128,7 +2131,7 @@ void MacroAssembler::StoreNumberToDoubleElements( if (emit_debug_code()) { vmrs(ip); tst(ip, Operand(kVFPDefaultNaNModeControlBit)); - Assert(ne, kDefaultNaNModeNotSet); + Assert(ne, "Default NaN mode not set"); } VFPCanonicalizeNaN(double_scratch); b(&store); @@ -2378,7 +2381,7 @@ void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function, if (emit_debug_code()) { ldr(r1, MemOperand(r7, kLevelOffset)); cmp(r1, r6); - Check(eq, kUnexpectedLevelAfterReturnFromApiCall); + Check(eq, "Unexpected level after return from api call"); } sub(r6, r6, Operand(1)); str(r6, MemOperand(r7, kLevelOffset)); @@ -2779,9 +2782,9 @@ void MacroAssembler::DecrementCounter(StatsCounter* counter, int value, } -void MacroAssembler::Assert(Condition cond, BailoutReason reason) { +void MacroAssembler::Assert(Condition cond, const char* msg) { if (emit_debug_code()) - Check(cond, reason); + Check(cond, msg); } @@ -2800,23 +2803,23 @@ void MacroAssembler::AssertFastElements(Register elements) { LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex); cmp(elements, ip); b(eq, &ok); - Abort(kJSObjectWithFastElementsMapHasSlowElements); + Abort("JSObject with fast elements map has slow elements"); bind(&ok); pop(elements); } } -void MacroAssembler::Check(Condition cond, BailoutReason reason) { +void MacroAssembler::Check(Condition cond, const char* msg) { Label L; b(cond, &L); - Abort(reason); + Abort(msg); // will not return here bind(&L); } -void MacroAssembler::Abort(BailoutReason reason) { +void MacroAssembler::Abort(const char* msg) { Label abort_start; bind(&abort_start); // We want to pass the msg string like a smi to avoid GC @@ -2824,7 +2827,6 @@ void MacroAssembler::Abort(BailoutReason reason) { // properly. Instead, we pass an aligned pointer that is // a proper v8 smi, but also pass the alignment difference // from the real pointer as a smi. - const char* msg = GetBailoutReason(reason); intptr_t p1 = reinterpret_cast<intptr_t>(msg); intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag; ASSERT(reinterpret_cast<Object*>(p0)->IsSmi()); @@ -2967,7 +2969,7 @@ void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK); b(&ok); bind(&fail); - Abort(kGlobalFunctionsMustHaveInitialMap); + Abort("Global functions must have initial map"); bind(&ok); } } @@ -3036,7 +3038,7 @@ void MacroAssembler::AssertNotSmi(Register object) { if (emit_debug_code()) { STATIC_ASSERT(kSmiTag == 0); tst(object, Operand(kSmiTagMask)); - Check(ne, kOperandIsASmi); + Check(ne, "Operand is a smi"); } } @@ -3045,7 +3047,7 @@ void MacroAssembler::AssertSmi(Register object) { if (emit_debug_code()) { STATIC_ASSERT(kSmiTag == 0); tst(object, Operand(kSmiTagMask)); - Check(eq, kOperandIsNotSmi); + Check(eq, "Operand is not smi"); } } @@ -3054,12 +3056,12 @@ void MacroAssembler::AssertString(Register object) { if (emit_debug_code()) { STATIC_ASSERT(kSmiTag == 0); tst(object, Operand(kSmiTagMask)); - Check(ne, kOperandIsASmiAndNotAString); + Check(ne, "Operand is a smi and not a string"); push(object); ldr(object, FieldMemOperand(object, HeapObject::kMapOffset)); CompareInstanceType(object, object, FIRST_NONSTRING_TYPE); pop(object); - Check(lo, kOperandIsNotAString); + Check(lo, "Operand is not a string"); } } @@ -3068,12 +3070,12 @@ void MacroAssembler::AssertName(Register object) { if (emit_debug_code()) { STATIC_ASSERT(kSmiTag == 0); tst(object, Operand(kSmiTagMask)); - Check(ne, kOperandIsASmiAndNotAName); + Check(ne, "Operand is a smi and not a name"); push(object); ldr(object, FieldMemOperand(object, HeapObject::kMapOffset)); CompareInstanceType(object, object, LAST_NAME_TYPE); pop(object); - Check(le, kOperandIsNotAName); + Check(le, "Operand is not a name"); } } @@ -3082,7 +3084,7 @@ void MacroAssembler::AssertName(Register object) { void MacroAssembler::AssertIsRoot(Register reg, Heap::RootListIndex index) { if (emit_debug_code()) { CompareRoot(reg, index); - Check(eq, kHeapNumberMapRegisterClobbered); + Check(eq, "HeapNumberMap register clobbered."); } } @@ -3228,7 +3230,7 @@ void MacroAssembler::CopyBytes(Register src, bind(&word_loop); if (emit_debug_code()) { tst(src, Operand(kPointerSize - 1)); - Assert(eq, kExpectingAlignmentForCopyBytes); + Assert(eq, "Expecting alignment for CopyBytes"); } cmp(length, Operand(kPointerSize)); b(lt, &byte_loop); @@ -3492,7 +3494,7 @@ void MacroAssembler::GetRelocatedValueLocation(Register ldr_location, // Check that the instruction is a ldr reg, [pc + offset] . and_(result, result, Operand(kLdrPCPattern)); cmp(result, Operand(kLdrPCPattern)); - Check(eq, kTheInstructionToPatchShouldBeALoadFromPc); + Check(eq, "The instruction to patch should be a load from pc."); // Result was clobbered. Restore it. ldr(result, MemOperand(ldr_location)); } diff --git a/chromium/v8/src/arm/macro-assembler-arm.h b/chromium/v8/src/arm/macro-assembler-arm.h index 8b9fa2b2216..38308e5cdef 100644 --- a/chromium/v8/src/arm/macro-assembler-arm.h +++ b/chromium/v8/src/arm/macro-assembler-arm.h @@ -144,8 +144,6 @@ class MacroAssembler: public Assembler { Condition cond = al); void Call(Label* target); - void Push(Register src) { push(src); } - void Pop(Register dst) { pop(dst); } // Register move. May do nothing if the registers are identical. void Move(Register dst, Handle<Object> value); @@ -1138,14 +1136,14 @@ class MacroAssembler: public Assembler { // Calls Abort(msg) if the condition cond is not satisfied. // Use --debug_code to enable. - void Assert(Condition cond, BailoutReason reason); + void Assert(Condition cond, const char* msg); void AssertFastElements(Register elements); // Like Assert(), but always enabled. - void Check(Condition cond, BailoutReason reason); + void Check(Condition cond, const char* msg); // Print a message to stdout and abort execution. - void Abort(BailoutReason msg); + void Abort(const char* msg); // Verify restrictions about code generated in stubs. void set_generating_stub(bool value) { generating_stub_ = value; } diff --git a/chromium/v8/src/array-iterator.js b/chromium/v8/src/array-iterator.js index defd7342ab2..8f1ab47b8a2 100644 --- a/chromium/v8/src/array-iterator.js +++ b/chromium/v8/src/array-iterator.js @@ -77,15 +77,16 @@ function ArrayIteratorNext() { return CreateIteratorResultObject(void 0, true); } + var elementKey = ToString(index); iterator[arrayIteratorNextIndexSymbol] = index + 1; if (itemKind == ARRAY_ITERATOR_KIND_VALUES) - return CreateIteratorResultObject(array[index], false); + return CreateIteratorResultObject(array[elementKey], false); if (itemKind == ARRAY_ITERATOR_KIND_ENTRIES) - return CreateIteratorResultObject([index, array[index]], false); + return CreateIteratorResultObject([elementKey, array[elementKey]], false); - return CreateIteratorResultObject(index, false); + return CreateIteratorResultObject(elementKey, false); } function ArrayEntries() { diff --git a/chromium/v8/src/assert-scope.h b/chromium/v8/src/assert-scope.h index 269b280d027..13adbd0f9c5 100644 --- a/chromium/v8/src/assert-scope.h +++ b/chromium/v8/src/assert-scope.h @@ -41,7 +41,6 @@ enum PerThreadAssertType { HANDLE_ALLOCATION_ASSERT, HANDLE_DEREFERENCE_ASSERT, DEFERRED_HANDLE_DEREFERENCE_ASSERT, - CODE_DEPENDENCY_CHANGE_ASSERT, LAST_PER_THREAD_ASSERT_TYPE }; @@ -171,14 +170,6 @@ typedef PerThreadAssertScope<DEFERRED_HANDLE_DEREFERENCE_ASSERT, false> typedef PerThreadAssertScope<DEFERRED_HANDLE_DEREFERENCE_ASSERT, true> AllowDeferredHandleDereference; -// Scope to document where we do not expect deferred handles to be dereferenced. -typedef PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, false> - DisallowCodeDependencyChange; - -// Scope to introduce an exception to DisallowDeferredHandleDereference. -typedef PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, true> - AllowCodeDependencyChange; - } } // namespace v8::internal #endif // V8_ASSERT_SCOPE_H_ diff --git a/chromium/v8/src/ast.cc b/chromium/v8/src/ast.cc index 23b680d47f4..e0bca67aab1 100644 --- a/chromium/v8/src/ast.cc +++ b/chromium/v8/src/ast.cc @@ -273,8 +273,7 @@ void ObjectLiteral::CalculateEmitStore(Zone* zone) { uint32_t hash = literal->Hash(); // If the key of a computed property is in the table, do not emit // a store for the property later. - if ((property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL || - property->kind() == ObjectLiteral::Property::COMPUTED) && + if (property->kind() == ObjectLiteral::Property::COMPUTED && table.Lookup(literal, hash, false, allocator) != NULL) { property->set_emit_store(false); } else { @@ -305,6 +304,17 @@ void UnaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { } +bool UnaryOperation::ResultOverwriteAllowed() { + switch (op_) { + case Token::BIT_NOT: + case Token::SUB: + return true; + default: + return false; + } +} + + void BinaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { // TODO(olivf) If this Operation is used in a test context, then the right // hand side has a ToBoolean stub and we want to collect the type information. diff --git a/chromium/v8/src/ast.h b/chromium/v8/src/ast.h index a8b74213adb..f14156f93c6 100644 --- a/chromium/v8/src/ast.h +++ b/chromium/v8/src/ast.h @@ -259,7 +259,6 @@ class Statement: public AstNode { Statement() : statement_pos_(RelocInfo::kNoPosition) {} bool IsEmpty() { return AsEmptyStatement() != NULL; } - virtual bool IsJump() const { return false; } void set_statement_pos(int statement_pos) { statement_pos_ = statement_pos; } int statement_pos() const { return statement_pos_; } @@ -292,6 +291,7 @@ class SmallMapList { } void Add(Handle<Map> handle, Zone* zone) { + ASSERT(!handle->is_deprecated()); list_.Add(handle.location(), zone); } @@ -389,7 +389,7 @@ class Expression: public AstNode { protected: explicit Expression(Isolate* isolate) - : bounds_(Bounds::Unbounded(isolate)), + : bounds_(Type::None(), Type::Any(), isolate), id_(GetNextId(isolate)), test_id_(GetNextId(isolate)) {} void set_to_boolean_types(byte types) { to_boolean_types_ = types; } @@ -459,11 +459,6 @@ class Block: public BreakableStatement { ZoneList<Statement*>* statements() { return &statements_; } bool is_initializer_block() const { return is_initializer_block_; } - virtual bool IsJump() const { - return !statements_.is_empty() && statements_.last()->IsJump() - && labels() == NULL; // Good enough as an approximation... - } - Scope* scope() const { return scope_; } void set_scope(Scope* scope) { scope_ = scope; } @@ -1014,7 +1009,6 @@ class ExpressionStatement: public Statement { void set_expression(Expression* e) { expression_ = e; } Expression* expression() const { return expression_; } - virtual bool IsJump() const { return expression_->IsThrow(); } protected: explicit ExpressionStatement(Expression* expression) @@ -1025,16 +1019,7 @@ class ExpressionStatement: public Statement { }; -class JumpStatement: public Statement { - public: - virtual bool IsJump() const { return true; } - - protected: - JumpStatement() {} -}; - - -class ContinueStatement: public JumpStatement { +class ContinueStatement: public Statement { public: DECLARE_NODE_TYPE(ContinueStatement) @@ -1049,7 +1034,7 @@ class ContinueStatement: public JumpStatement { }; -class BreakStatement: public JumpStatement { +class BreakStatement: public Statement { public: DECLARE_NODE_TYPE(BreakStatement) @@ -1064,7 +1049,7 @@ class BreakStatement: public JumpStatement { }; -class ReturnStatement: public JumpStatement { +class ReturnStatement: public Statement { public: DECLARE_NODE_TYPE(ReturnStatement) @@ -1183,11 +1168,6 @@ class IfStatement: public Statement { Statement* then_statement() const { return then_statement_; } Statement* else_statement() const { return else_statement_; } - virtual bool IsJump() const { - return HasThenStatement() && then_statement()->IsJump() - && HasElseStatement() && else_statement()->IsJump(); - } - BailoutId IfId() const { return if_id_; } BailoutId ThenId() const { return then_id_; } BailoutId ElseId() const { return else_id_; } @@ -1847,6 +1827,8 @@ class UnaryOperation: public Expression { public: DECLARE_NODE_TYPE(UnaryOperation) + virtual bool ResultOverwriteAllowed(); + Token::Value op() const { return op_; } Expression* expression() const { return expression_; } virtual int position() const { return pos_; } @@ -1854,6 +1836,8 @@ class UnaryOperation: public Expression { BailoutId MaterializeTrueId() { return materialize_true_id_; } BailoutId MaterializeFalseId() { return materialize_false_id_; } + TypeFeedbackId UnaryOperationFeedbackId() const { return reuse(id()); } + virtual void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle); protected: diff --git a/chromium/v8/src/atomicops_internals_tsan.h b/chromium/v8/src/atomicops_internals_tsan.h index b5162bad9f6..e52c26c2fe2 100644 --- a/chromium/v8/src/atomicops_internals_tsan.h +++ b/chromium/v8/src/atomicops_internals_tsan.h @@ -32,12 +32,6 @@ #ifndef V8_ATOMICOPS_INTERNALS_TSAN_H_ #define V8_ATOMICOPS_INTERNALS_TSAN_H_ -namespace v8 { -namespace internal { - -#ifndef TSAN_INTERFACE_ATOMIC_H -#define TSAN_INTERFACE_ATOMIC_H - // This struct is not part of the public API of this module; clients may not // use it. (However, it's exported via BASE_EXPORT because clients implicitly // do use it at link time by inlining these functions.) @@ -53,6 +47,12 @@ extern struct AtomicOps_x86CPUFeatureStruct #define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory") +namespace v8 { +namespace internal { + +#ifndef TSAN_INTERFACE_ATOMIC_H +#define TSAN_INTERFACE_ATOMIC_H + #ifdef __cplusplus extern "C" { #endif diff --git a/chromium/v8/src/bootstrapper.cc b/chromium/v8/src/bootstrapper.cc index 2a385aa4865..c2cc6efc45f 100644 --- a/chromium/v8/src/bootstrapper.cc +++ b/chromium/v8/src/bootstrapper.cc @@ -2085,11 +2085,6 @@ bool Genesis::InstallExperimentalNatives() { "native harmony-string.js") == 0) { if (!CompileExperimentalBuiltin(isolate(), i)) return false; } - if (FLAG_harmony_arrays && - strcmp(ExperimentalNatives::GetScriptName(i).start(), - "native harmony-array.js") == 0) { - if (!CompileExperimentalBuiltin(isolate(), i)) return false; - } } InstallExperimentalNativeFunctions(); diff --git a/chromium/v8/src/builtins.h b/chromium/v8/src/builtins.h index bb36c0251d9..73a2e964590 100644 --- a/chromium/v8/src/builtins.h +++ b/chromium/v8/src/builtins.h @@ -259,6 +259,8 @@ enum BuiltinExtraArguments { V(BIT_OR, 1) \ V(BIT_AND, 1) \ V(BIT_XOR, 1) \ + V(UNARY_MINUS, 0) \ + V(BIT_NOT, 0) \ V(SHL, 1) \ V(SAR, 1) \ V(SHR, 1) \ diff --git a/chromium/v8/src/code-stubs-hydrogen.cc b/chromium/v8/src/code-stubs-hydrogen.cc index 4f6db35dd93..9ca6a47f2ee 100644 --- a/chromium/v8/src/code-stubs-hydrogen.cc +++ b/chromium/v8/src/code-stubs-hydrogen.cc @@ -41,13 +41,13 @@ static LChunk* OptimizeGraph(HGraph* graph) { DisallowHandleDereference no_deref; ASSERT(graph != NULL); - BailoutReason bailout_reason = kNoReason; + SmartArrayPointer<char> bailout_reason; if (!graph->Optimize(&bailout_reason)) { - FATAL(GetBailoutReason(bailout_reason)); + FATAL(bailout_reason.is_empty() ? "unknown" : *bailout_reason); } LChunk* chunk = LChunk::NewChunk(graph); if (chunk == NULL) { - FATAL(GetBailoutReason(graph->info()->bailout_reason())); + FATAL(graph->info()->bailout_reason()); } return chunk; } @@ -92,7 +92,7 @@ class CodeStubGraphBuilderBase : public HGraphBuilder { } ~ArrayContextChecker() { - checker_.ElseDeopt("Array constructor called from different context"); + checker_.ElseDeopt(); checker_.End(); } private: @@ -233,7 +233,7 @@ class CodeStubGraphBuilder: public CodeStubGraphBuilderBase { IfBuilder builder(this); builder.IfNot<HCompareObjectEqAndBranch, HValue*>(undefined, undefined); builder.Then(); - builder.ElseDeopt("Forced deopt to runtime"); + builder.ElseDeopt(); return undefined; } @@ -387,7 +387,7 @@ HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() { length)); } - checker.ElseDeopt("Uninitialized boilerplate literals"); + checker.ElseDeopt(); checker.End(); return environment()->Pop(); @@ -434,7 +434,7 @@ HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() { } environment()->Push(object); - checker.ElseDeopt("Uninitialized boilerplate in fast clone"); + checker.ElseDeopt(); checker.End(); return environment()->Pop(); @@ -802,6 +802,44 @@ Handle<Code> CompareNilICStub::GenerateCode() { template <> +HValue* CodeStubGraphBuilder<UnaryOpStub>::BuildCodeInitializedStub() { + UnaryOpStub* stub = casted_stub(); + Handle<Type> type = stub->GetType(graph()->isolate()); + HValue* input = GetParameter(0); + + // Prevent unwanted HChange being inserted to ensure that the stub + // deopts on newly encountered types. + if (!type->Maybe(Type::Double())) { + input = Add<HForceRepresentation>(input, Representation::Smi()); + } + + if (!type->Is(Type::Number())) { + // If we expect to see other things than Numbers, we will create a generic + // stub, which handles all numbers and calls into the runtime for the rest. + IfBuilder if_number(this); + if_number.If<HIsNumberAndBranch>(input); + if_number.Then(); + HInstruction* res = BuildUnaryMathOp(input, type, stub->operation()); + if_number.Return(AddInstruction(res)); + if_number.Else(); + HValue* function = AddLoadJSBuiltin(stub->ToJSBuiltin()); + Add<HPushArgument>(GetParameter(0)); + HValue* result = Add<HInvokeFunction>(function, 1); + if_number.Return(result); + if_number.End(); + return graph()->GetConstantUndefined(); + } + + return AddInstruction(BuildUnaryMathOp(input, type, stub->operation())); +} + + +Handle<Code> UnaryOpStub::GenerateCode() { + return DoGenerateCode(this); +} + + +template <> HValue* CodeStubGraphBuilder<ToBooleanStub>::BuildCodeInitializedStub() { ToBooleanStub* stub = casted_stub(); @@ -844,7 +882,7 @@ HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() { IfBuilder builder(this); builder.If<HCompareObjectEqAndBranch>(cell_contents, value); builder.Then(); - builder.ElseDeopt("Unexpected cell contents in constant global store"); + builder.ElseDeopt(); builder.End(); } else { // Load the payload of the global parameter cell. A hole indicates that the @@ -854,7 +892,7 @@ HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() { HValue* hole_value = Add<HConstant>(hole); builder.If<HCompareObjectEqAndBranch>(cell_contents, hole_value); builder.Then(); - builder.Deopt("Unexpected cell contents in global store"); + builder.Deopt(); builder.Else(); Add<HStoreNamedField>(cell, access, value); builder.End(); @@ -878,8 +916,7 @@ HValue* CodeStubGraphBuilder<ElementsTransitionAndStoreStub>::BuildCodeStub() { if (FLAG_trace_elements_transitions) { // Tracing elements transitions is the job of the runtime. - Add<HDeoptimize>("Deopt due to --trace-elements-transitions", - Deoptimizer::EAGER); + Add<HDeoptimize>(Deoptimizer::EAGER); } else { info()->MarkAsSavesCallerDoubles(); diff --git a/chromium/v8/src/code-stubs.cc b/chromium/v8/src/code-stubs.cc index f656bf7d96b..5f6616ea07a 100644 --- a/chromium/v8/src/code-stubs.cc +++ b/chromium/v8/src/code-stubs.cc @@ -204,6 +204,71 @@ void CodeStub::PrintName(StringStream* stream) { } +Builtins::JavaScript UnaryOpStub::ToJSBuiltin() { + switch (operation_) { + default: + UNREACHABLE(); + case Token::SUB: + return Builtins::UNARY_MINUS; + case Token::BIT_NOT: + return Builtins::BIT_NOT; + } +} + + +Handle<JSFunction> UnaryOpStub::ToJSFunction(Isolate* isolate) { + Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object()); + Object* builtin = builtins->javascript_builtin(ToJSBuiltin()); + return Handle<JSFunction>(JSFunction::cast(builtin), isolate); +} + + +MaybeObject* UnaryOpStub::Result(Handle<Object> object, Isolate* isolate) { + Handle<JSFunction> builtin_function = ToJSFunction(isolate); + bool caught_exception; + Handle<Object> result = Execution::Call(builtin_function, object, + 0, NULL, &caught_exception); + if (caught_exception) { + return Failure::Exception(); + } + return *result; +} + + +void UnaryOpStub::UpdateStatus(Handle<Object> object) { + State old_state(state_); + if (object->IsSmi()) { + state_.Add(SMI); + if (operation_ == Token::SUB && *object == 0) { + // The result (-0) has to be represented as double. + state_.Add(HEAP_NUMBER); + } + } else if (object->IsHeapNumber()) { + state_.Add(HEAP_NUMBER); + } else { + state_.Add(GENERIC); + } + TraceTransition(old_state, state_); +} + + +Handle<Type> UnaryOpStub::GetType(Isolate* isolate) { + if (state_.Contains(GENERIC)) { + return handle(Type::Any(), isolate); + } + Handle<Type> type = handle(Type::None(), isolate); + if (state_.Contains(SMI)) { + type = handle( + Type::Union(type, handle(Type::Smi(), isolate)), isolate); + } + if (state_.Contains(HEAP_NUMBER)) { + type = handle( + Type::Union(type, handle(Type::Double(), isolate)), isolate); + } + return type; +} + + void BinaryOpStub::Generate(MacroAssembler* masm) { // Explicitly allow generation of nested stubs. It is safe here because // generation code does not use any raw pointers. @@ -289,6 +354,29 @@ void BinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) { #undef __ +void UnaryOpStub::PrintBaseName(StringStream* stream) { + CodeStub::PrintBaseName(stream); + if (operation_ == Token::SUB) stream->Add("Minus"); + if (operation_ == Token::BIT_NOT) stream->Add("Not"); +} + + +void UnaryOpStub::PrintState(StringStream* stream) { + state_.Print(stream); +} + + +void UnaryOpStub::State::Print(StringStream* stream) const { + stream->Add("("); + SimpleListPrinter printer(stream); + if (IsEmpty()) printer.Add("None"); + if (Contains(GENERIC)) printer.Add("Generic"); + if (Contains(HEAP_NUMBER)) printer.Add("HeapNumber"); + if (Contains(SMI)) printer.Add("Smi"); + stream->Add(")"); +} + + void BinaryOpStub::PrintName(StringStream* stream) { const char* op_name = Token::Name(op_); const char* overwrite_name; @@ -469,9 +557,6 @@ void CompareNilICStub::UpdateStatus(Handle<Object> object) { template<class StateType> void HydrogenCodeStub::TraceTransition(StateType from, StateType to) { - // Note: Although a no-op transition is semantically OK, it is hinting at a - // bug somewhere in our state transition machinery. - ASSERT(from != to); #ifdef DEBUG if (!FLAG_trace_ic) return; char buffer[100]; diff --git a/chromium/v8/src/code-stubs.h b/chromium/v8/src/code-stubs.h index c58acd6b16d..84d9b023b3a 100644 --- a/chromium/v8/src/code-stubs.h +++ b/chromium/v8/src/code-stubs.h @@ -40,6 +40,7 @@ namespace internal { #define CODE_STUB_LIST_ALL_PLATFORMS(V) \ V(CallFunction) \ V(CallConstruct) \ + V(UnaryOp) \ V(BinaryOp) \ V(StringAdd) \ V(SubString) \ @@ -592,6 +593,73 @@ class StoreGlobalStub : public HydrogenCodeStub { }; +class UnaryOpStub : public HydrogenCodeStub { + public: + // Stub without type info available -> construct uninitialized + explicit UnaryOpStub(Token::Value operation) + : HydrogenCodeStub(UNINITIALIZED), operation_(operation) { } + explicit UnaryOpStub(Code::ExtraICState ic_state) : + state_(StateBits::decode(ic_state)), + operation_(OperatorBits::decode(ic_state)) { } + + virtual void InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor); + + virtual Code::Kind GetCodeKind() const { return Code::UNARY_OP_IC; } + virtual InlineCacheState GetICState() { + if (state_.Contains(GENERIC)) { + return MEGAMORPHIC; + } else if (state_.IsEmpty()) { + return PREMONOMORPHIC; + } else { + return MONOMORPHIC; + } + } + virtual Code::ExtraICState GetExtraICState() { + return OperatorBits::encode(operation_) | + StateBits::encode(state_.ToIntegral()); + } + + Token::Value operation() { return operation_; } + Handle<JSFunction> ToJSFunction(Isolate* isolate); + Builtins::JavaScript ToJSBuiltin(); + + void UpdateStatus(Handle<Object> object); + MaybeObject* Result(Handle<Object> object, Isolate* isolate); + Handle<Code> GenerateCode(); + Handle<Type> GetType(Isolate* isolate); + + protected: + void PrintState(StringStream* stream); + void PrintBaseName(StringStream* stream); + + private: + enum UnaryOpType { + SMI, + HEAP_NUMBER, + GENERIC, + NUMBER_OF_TYPES + }; + + class State : public EnumSet<UnaryOpType, byte> { + public: + State() : EnumSet<UnaryOpType, byte>() { } + explicit State(byte bits) : EnumSet<UnaryOpType, byte>(bits) { } + void Print(StringStream* stream) const; + }; + + class StateBits : public BitField<int, 0, NUMBER_OF_TYPES> { }; + class OperatorBits : public BitField<Token::Value, NUMBER_OF_TYPES, 8> { }; + + State state_; + Token::Value operation_; + + virtual CodeStub::Major MajorKey() { return UnaryOp; } + virtual int NotMissMinorKey() { return GetExtraICState(); } +}; + + class FastCloneShallowArrayStub : public HydrogenCodeStub { public: // Maximum length of copied elements array. diff --git a/chromium/v8/src/compiler.cc b/chromium/v8/src/compiler.cc index f6e5daac854..3c51baa30e9 100644 --- a/chromium/v8/src/compiler.cc +++ b/chromium/v8/src/compiler.cc @@ -120,7 +120,6 @@ void CompilationInfo::Initialize(Isolate* isolate, return; } mode_ = V8::UseCrankshaft() ? mode : NONOPT; - abort_due_to_dependency_ = false; if (script_->type()->value() == Script::TYPE_NATIVE) { MarkAsNative(); } @@ -128,7 +127,7 @@ void CompilationInfo::Initialize(Isolate* isolate, ASSERT(language_mode() == CLASSIC_MODE); SetLanguageMode(shared_info_->language_mode()); } - set_bailout_reason(kUnknown); + set_bailout_reason("unknown"); } @@ -343,7 +342,7 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() { const int kMaxOptCount = FLAG_deopt_every_n_times == 0 ? FLAG_max_opt_count : 1000; if (info()->opt_count() > kMaxOptCount) { - info()->set_bailout_reason(kOptimizedTooManyTimes); + info()->set_bailout_reason("optimized too many times"); return AbortOptimization(); } @@ -357,14 +356,14 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() { const int parameter_limit = -LUnallocated::kMinFixedSlotIndex; Scope* scope = info()->scope(); if ((scope->num_parameters() + 1) > parameter_limit) { - info()->set_bailout_reason(kTooManyParameters); + info()->set_bailout_reason("too many parameters"); return AbortOptimization(); } const int locals_limit = LUnallocated::kMaxFixedSlotIndex; if (!info()->osr_ast_id().IsNone() && scope->num_parameters() + 1 + scope->num_stack_slots() > locals_limit) { - info()->set_bailout_reason(kTooManyParametersLocals); + info()->set_bailout_reason("too many parameters/locals"); return AbortOptimization(); } @@ -447,12 +446,6 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() { } } - if (info()->HasAbortedDueToDependencyChange()) { - info_->set_bailout_reason(kBailedOutDueToDependencyChange); - info_->AbortOptimization(); - return SetLastStatus(BAILED_OUT); - } - return SetLastStatus(SUCCEEDED); } @@ -461,14 +454,13 @@ OptimizingCompiler::Status OptimizingCompiler::OptimizeGraph() { DisallowHeapAllocation no_allocation; DisallowHandleAllocation no_handles; DisallowHandleDereference no_deref; - DisallowCodeDependencyChange no_dependency_change; ASSERT(last_status() == SUCCEEDED); Timer t(this, &time_taken_to_optimize_); ASSERT(graph_ != NULL); - BailoutReason bailout_reason = kNoReason; + SmartArrayPointer<char> bailout_reason; if (!graph_->Optimize(&bailout_reason)) { - if (bailout_reason == kNoReason) graph_builder_->Bailout(bailout_reason); + if (!bailout_reason.is_empty()) graph_builder_->Bailout(*bailout_reason); return SetLastStatus(BAILED_OUT); } else { chunk_ = LChunk::NewChunk(graph_); @@ -482,8 +474,6 @@ OptimizingCompiler::Status OptimizingCompiler::OptimizeGraph() { OptimizingCompiler::Status OptimizingCompiler::GenerateAndInstallCode() { ASSERT(last_status() == SUCCEEDED); - ASSERT(!info()->HasAbortedDueToDependencyChange()); - DisallowCodeDependencyChange no_dependency_change; { // Scope for timer. Timer timer(this, &time_taken_to_codegen_); ASSERT(chunk_ != NULL); @@ -495,9 +485,7 @@ OptimizingCompiler::Status OptimizingCompiler::GenerateAndInstallCode() { DisallowDeferredHandleDereference no_deferred_handle_deref; Handle<Code> optimized_code = chunk_->Codegen(); if (optimized_code.is_null()) { - if (info()->bailout_reason() == kNoReason) { - info()->set_bailout_reason(kCodeGenerationFailed); - } + info()->set_bailout_reason("code generation failed"); return AbortOptimization(); } info()->SetCode(optimized_code); @@ -792,7 +780,7 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, if (!result.is_null()) { // Explicitly disable optimization for eval code. We're not yet prepared // to handle eval-code in the optimizing compiler. - result->DisableOptimization(kEval); + result->DisableOptimization("eval"); // If caller is strict mode, the result must be in strict mode or // extended mode as well, but not the other way around. Consider: @@ -825,7 +813,6 @@ static bool InstallFullCode(CompilationInfo* info) { // was flushed. By setting the code object last we avoid this. Handle<SharedFunctionInfo> shared = info->shared_info(); Handle<Code> code = info->code(); - CHECK(code->kind() == Code::FUNCTION); Handle<JSFunction> function = info->closure(); Handle<ScopeInfo> scope_info = ScopeInfo::Create(info->scope(), info->zone()); @@ -983,9 +970,7 @@ void Compiler::RecompileParallel(Handle<JSFunction> closure) { if (!isolate->optimizing_compiler_thread()->IsQueueAvailable()) { if (FLAG_trace_parallel_recompilation) { - PrintF(" ** Compilation queue full, will retry optimizing "); - closure->PrintName(); - PrintF(" on next run.\n"); + PrintF(" ** Compilation queue, will retry opting on next run.\n"); } return; } @@ -1070,13 +1055,13 @@ void Compiler::InstallOptimizedCode(OptimizingCompiler* optimizing_compiler) { // the unoptimized code. OptimizingCompiler::Status status = optimizing_compiler->last_status(); if (info->HasAbortedDueToDependencyChange()) { - info->set_bailout_reason(kBailedOutDueToDependencyChange); + info->set_bailout_reason("bailed out due to dependent map"); status = optimizing_compiler->AbortOptimization(); } else if (status != OptimizingCompiler::SUCCEEDED) { - info->set_bailout_reason(kFailedBailedOutLastTime); + info->set_bailout_reason("failed/bailed out last time"); status = optimizing_compiler->AbortOptimization(); } else if (isolate->DebuggerHasBreakPoints()) { - info->set_bailout_reason(kDebuggerIsActive); + info->set_bailout_reason("debugger is active"); status = optimizing_compiler->AbortOptimization(); } else { status = optimizing_compiler->GenerateAndInstallCode(); diff --git a/chromium/v8/src/compiler.h b/chromium/v8/src/compiler.h index 7d442f9d461..d36e488b174 100644 --- a/chromium/v8/src/compiler.h +++ b/chromium/v8/src/compiler.h @@ -199,11 +199,6 @@ class CompilationInfo { return IsCompilingForDebugging::decode(flags_); } - bool ShouldTrapOnDeopt() const { - return (FLAG_trap_on_deopt && IsOptimizing()) || - (FLAG_trap_on_stub_deopt && IsStub()); - } - bool has_global_object() const { return !closure().is_null() && (closure()->context()->global_object() != NULL); @@ -263,8 +258,8 @@ class CompilationInfo { SaveHandle(&script_); } - BailoutReason bailout_reason() const { return bailout_reason_; } - void set_bailout_reason(BailoutReason reason) { bailout_reason_ = reason; } + const char* bailout_reason() const { return bailout_reason_; } + void set_bailout_reason(const char* reason) { bailout_reason_ = reason; } int prologue_offset() const { ASSERT_NE(kPrologueOffsetNotSet, prologue_offset_); @@ -298,13 +293,11 @@ class CompilationInfo { } void AbortDueToDependencyChange() { - ASSERT(!isolate()->optimizing_compiler_thread()->IsOptimizerThread()); - abort_due_to_dependency_ = true; + mode_ = DEPENDENCY_CHANGE_ABORT; } bool HasAbortedDueToDependencyChange() { - ASSERT(!isolate()->optimizing_compiler_thread()->IsOptimizerThread()); - return abort_due_to_dependency_; + return mode_ == DEPENDENCY_CHANGE_ABORT; } protected: @@ -328,7 +321,8 @@ class CompilationInfo { BASE, OPTIMIZE, NONOPT, - STUB + STUB, + DEPENDENCY_CHANGE_ABORT }; void Initialize(Isolate* isolate, Mode mode, Zone* zone); @@ -402,9 +396,6 @@ class CompilationInfo { Mode mode_; BailoutId osr_ast_id_; - // Flag whether compilation needs to be aborted due to dependency change. - bool abort_due_to_dependency_; - // The zone from which the compilation pipeline working on this // CompilationInfo allocates. Zone* zone_; @@ -421,7 +412,7 @@ class CompilationInfo { } } - BailoutReason bailout_reason_; + const char* bailout_reason_; int prologue_offset_; diff --git a/chromium/v8/src/cpu-profiler.cc b/chromium/v8/src/cpu-profiler.cc index 747542f7378..0a83b85f505 100644 --- a/chromium/v8/src/cpu-profiler.cc +++ b/chromium/v8/src/cpu-profiler.cc @@ -106,7 +106,7 @@ bool ProfilerEventsProcessor::ProcessCodeEvent() { bool ProfilerEventsProcessor::ProcessTicks() { while (true) { - while (!ticks_from_vm_buffer_.IsEmpty() + if (!ticks_from_vm_buffer_.IsEmpty() && ticks_from_vm_buffer_.Peek()->order == last_processed_code_event_id_) { TickSampleEventRecord record; diff --git a/chromium/v8/src/cpu-profiler.h b/chromium/v8/src/cpu-profiler.h index 1dd405e5d76..cbe3e3cf81d 100644 --- a/chromium/v8/src/cpu-profiler.h +++ b/chromium/v8/src/cpu-profiler.h @@ -241,7 +241,6 @@ class CpuProfiler : public CodeEventListener { ProfileGenerator* generator() const { return generator_; } ProfilerEventsProcessor* processor() const { return processor_; } - Isolate* isolate() const { return isolate_; } private: void StartProcessorIfNotStarted(); @@ -259,6 +258,7 @@ class CpuProfiler : public CodeEventListener { bool need_to_stop_sampler_; bool is_profiling_; + private: DISALLOW_COPY_AND_ASSIGN(CpuProfiler); }; diff --git a/chromium/v8/src/d8.cc b/chromium/v8/src/d8.cc index c7b66c2a150..6e7beebf549 100644 --- a/chromium/v8/src/d8.cc +++ b/chromium/v8/src/d8.cc @@ -1406,14 +1406,6 @@ bool Shell::SetOptions(int argc, char* argv[]) { #else options.num_parallel_files++; #endif // V8_SHARED - } else if (strcmp(argv[i], "--dump-heap-constants") == 0) { -#ifdef V8_SHARED - printf("D8 with shared library does not support constant dumping\n"); - return false; -#else - options.dump_heap_constants = true; - argv[i] = NULL; -#endif } #ifdef V8_SHARED else if (strcmp(argv[i], "--dump-counters") == 0) { @@ -1568,63 +1560,6 @@ static void SetStandaloneFlagsViaCommandLine() { #endif -#ifndef V8_SHARED -static void DumpHeapConstants(i::Isolate* isolate) { - i::Heap* heap = isolate->heap(); - - // Dump the INSTANCE_TYPES table to the console. - printf("# List of known V8 instance types.\n"); -#define DUMP_TYPE(T) printf(" %d: \"%s\",\n", i::T, #T); - printf("INSTANCE_TYPES = {\n"); - INSTANCE_TYPE_LIST(DUMP_TYPE) - printf("}\n"); -#undef DUMP_TYPE - - // Dump the KNOWN_MAP table to the console. - printf("\n# List of known V8 maps.\n"); -#define ROOT_LIST_CASE(type, name, camel_name) \ - if (n == NULL && o == heap->name()) n = #camel_name; -#define STRUCT_LIST_CASE(upper_name, camel_name, name) \ - if (n == NULL && o == heap->name##_map()) n = #camel_name "Map"; - i::HeapObjectIterator it(heap->map_space()); - printf("KNOWN_MAPS = {\n"); - for (i::Object* o = it.Next(); o != NULL; o = it.Next()) { - i::Map* m = i::Map::cast(o); - const char* n = NULL; - intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff; - int t = m->instance_type(); - ROOT_LIST(ROOT_LIST_CASE) - STRUCT_LIST(STRUCT_LIST_CASE) - if (n == NULL) continue; - printf(" 0x%05" V8PRIxPTR ": (%d, \"%s\"),\n", p, t, n); - } - printf("}\n"); -#undef STRUCT_LIST_CASE -#undef ROOT_LIST_CASE - - // Dump the KNOWN_OBJECTS table to the console. - printf("\n# List of known V8 objects.\n"); -#define ROOT_LIST_CASE(type, name, camel_name) \ - if (n == NULL && o == heap->name()) n = #camel_name; - i::OldSpaces spit(heap); - printf("KNOWN_OBJECTS = {\n"); - for (i::PagedSpace* s = spit.next(); s != NULL; s = spit.next()) { - i::HeapObjectIterator it(s); - const char* sname = AllocationSpaceName(s->identity()); - for (i::Object* o = it.Next(); o != NULL; o = it.Next()) { - const char* n = NULL; - intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff; - ROOT_LIST(ROOT_LIST_CASE) - if (n == NULL) continue; - printf(" (\"%s\", 0x%05" V8PRIxPTR "): \"%s\",\n", sname, p, n); - } - } - printf("}\n"); -#undef ROOT_LIST_CASE -} -#endif // V8_SHARED - - class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator { public: virtual void* Allocate(size_t length) { @@ -1668,13 +1603,6 @@ int Shell::Main(int argc, char* argv[]) { PerIsolateData data(isolate); InitializeDebugger(isolate); -#ifndef V8_SHARED - if (options.dump_heap_constants) { - DumpHeapConstants(reinterpret_cast<i::Isolate*>(isolate)); - return 0; - } -#endif - if (options.stress_opt || options.stress_deopt) { Testing::SetStressRunType(options.stress_opt ? Testing::kStressTypeOpt diff --git a/chromium/v8/src/d8.h b/chromium/v8/src/d8.h index 3b06985ca25..4f04342cf4d 100644 --- a/chromium/v8/src/d8.h +++ b/chromium/v8/src/d8.h @@ -231,7 +231,6 @@ class ShellOptions { stress_deopt(false), interactive_shell(false), test_shell(false), - dump_heap_constants(false), num_isolates(1), isolate_sources(NULL) { } @@ -255,7 +254,6 @@ class ShellOptions { bool stress_deopt; bool interactive_shell; bool test_shell; - bool dump_heap_constants; int num_isolates; SourceGroup* isolate_sources; }; diff --git a/chromium/v8/src/debug.cc b/chromium/v8/src/debug.cc index 4966713baab..a0b9884410f 100644 --- a/chromium/v8/src/debug.cc +++ b/chromium/v8/src/debug.cc @@ -159,6 +159,7 @@ void BreakLocationIterator::Next() { Code* code = Code::GetCodeFromTargetAddress(target); if ((code->is_inline_cache_stub() && !code->is_binary_op_stub() && + !code->is_unary_op_stub() && !code->is_compare_ic_stub() && !code->is_to_boolean_ic_stub()) || RelocInfo::IsConstructCall(rmode())) { @@ -409,9 +410,6 @@ bool BreakLocationIterator::IsStepInLocation(Isolate* isolate) { HandleScope scope(debug_info_->GetIsolate()); Address target = rinfo()->target_address(); Handle<Code> target_code(Code::GetCodeFromTargetAddress(target)); - if (target_code->kind() == Code::STUB) { - return target_code->major_key() == CodeStub::CallFunction; - } return target_code->is_call_stub() || target_code->is_keyed_call_stub(); } else { return false; @@ -2047,10 +2045,6 @@ void Debug::PrepareForBreakPoints() { // If preparing for the first break point make sure to deoptimize all // functions as debugging does not work with optimized code. if (!has_break_points_) { - if (FLAG_parallel_recompilation) { - isolate_->optimizing_compiler_thread()->Flush(); - } - Deoptimizer::DeoptimizeAll(isolate_); Handle<Code> lazy_compile = diff --git a/chromium/v8/src/deoptimizer.cc b/chromium/v8/src/deoptimizer.cc index dc9ffc51186..53b9b76377f 100644 --- a/chromium/v8/src/deoptimizer.cc +++ b/chromium/v8/src/deoptimizer.cc @@ -602,12 +602,6 @@ Deoptimizer::Deoptimizer(Isolate* isolate, deferred_objects_double_values_(0), deferred_objects_(0), deferred_heap_numbers_(0), - jsframe_functions_(0), - jsframe_has_adapted_arguments_(0), - materialized_values_(NULL), - materialized_objects_(NULL), - materialization_value_index_(0), - materialization_object_index_(0), trace_(false) { // For COMPILED_STUBs called from builtins, the function pointer is a SMI // indicating an internal frame. @@ -1214,15 +1208,7 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, unsigned output_offset = output_frame_size; for (int i = 0; i < parameter_count; ++i) { output_offset -= kPointerSize; - int deferred_object_index = deferred_objects_.length(); DoTranslateCommand(iterator, frame_index, output_offset); - // The allocated receiver of a construct stub frame is passed as the - // receiver parameter through the translation. It might be encoding - // a captured object, patch the slot address for a captured object. - if (i == 0 && deferred_objects_.length() > deferred_object_index) { - ASSERT(!deferred_objects_[deferred_object_index].is_arguments()); - deferred_objects_[deferred_object_index].patch_slot_address(top_address); - } } // Read caller's PC from the previous frame. @@ -1647,93 +1633,9 @@ void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator, } -Handle<Object> Deoptimizer::MaterializeNextHeapObject() { - int object_index = materialization_object_index_++; - ObjectMaterializationDescriptor desc = deferred_objects_[object_index]; - const int length = desc.object_length(); - - if (desc.duplicate_object() >= 0) { - // Found a previously materialized object by de-duplication. - object_index = desc.duplicate_object(); - materialized_objects_->Add(Handle<Object>()); - } else if (desc.is_arguments() && ArgumentsObjectIsAdapted(object_index)) { - // Use the arguments adapter frame we just built to materialize the - // arguments object. FunctionGetArguments can't throw an exception. - Handle<JSFunction> function = ArgumentsObjectFunction(object_index); - Handle<JSObject> arguments = Handle<JSObject>::cast( - Accessors::FunctionGetArguments(function)); - materialized_objects_->Add(arguments); - materialization_value_index_ += length; - } else if (desc.is_arguments()) { - // Construct an arguments object and copy the parameters to a newly - // allocated arguments object backing store. - Handle<JSFunction> function = ArgumentsObjectFunction(object_index); - Handle<JSObject> arguments = - isolate_->factory()->NewArgumentsObject(function, length); - Handle<FixedArray> array = isolate_->factory()->NewFixedArray(length); - ASSERT(array->length() == length); - arguments->set_elements(*array); - materialized_objects_->Add(arguments); - for (int i = 0; i < length; ++i) { - Handle<Object> value = MaterializeNextValue(); - array->set(i, *value); - } - } else { - // Dispatch on the instance type of the object to be materialized. - Handle<Map> map = Handle<Map>::cast(MaterializeNextValue()); - switch (map->instance_type()) { - case HEAP_NUMBER_TYPE: { - Handle<HeapNumber> number = - Handle<HeapNumber>::cast(MaterializeNextValue()); - materialized_objects_->Add(number); - materialization_value_index_ += kDoubleSize / kPointerSize - 1; - break; - } - case JS_OBJECT_TYPE: { - Handle<JSObject> object = - isolate_->factory()->NewJSObjectFromMap(map, NOT_TENURED, false); - materialized_objects_->Add(object); - Handle<Object> properties = MaterializeNextValue(); - Handle<Object> elements = MaterializeNextValue(); - object->set_properties(FixedArray::cast(*properties)); - object->set_elements(FixedArray::cast(*elements)); - for (int i = 0; i < length - 3; ++i) { - Handle<Object> value = MaterializeNextValue(); - object->FastPropertyAtPut(i, *value); - } - break; - } - default: - PrintF("[couldn't handle instance type %d]\n", map->instance_type()); - UNREACHABLE(); - } - } - - return materialized_objects_->at(object_index); -} - - -Handle<Object> Deoptimizer::MaterializeNextValue() { - int value_index = materialization_value_index_++; - Handle<Object> value = materialized_values_->at(value_index); - if (*value == isolate_->heap()->arguments_marker()) { - value = MaterializeNextHeapObject(); - } - return value; -} - - void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) { ASSERT_NE(DEBUGGER, bailout_type_); - // Walk all JavaScript output frames with the given frame iterator. - for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) { - if (frame_index != 0) it->Advance(); - JavaScriptFrame* frame = it->frame(); - jsframe_functions_.Add(handle(frame->function(), isolate_)); - jsframe_has_adapted_arguments_.Add(frame->has_adapted_arguments()); - } - // Handlify all tagged object values before triggering any allocation. List<Handle<Object> > values(deferred_objects_tagged_values_.length()); for (int i = 0; i < deferred_objects_tagged_values_.length(); ++i) { @@ -1750,7 +1652,7 @@ void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) { HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i]; Handle<Object> num = isolate_->factory()->NewNumber(d.value()); if (trace_) { - PrintF("Materialized a new heap number %p [%e] in slot %p\n", + PrintF("Materializing a new heap number %p [%e] in slot %p\n", reinterpret_cast<void*>(*num), d.value(), d.slot_address()); @@ -1758,52 +1660,62 @@ void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) { Memory::Object_at(d.slot_address()) = *num; } - // Materialize all heap numbers required for arguments/captured objects. + // Materialize all heap numbers required for arguments objects. for (int i = 0; i < values.length(); i++) { if (!values.at(i)->IsTheHole()) continue; double double_value = deferred_objects_double_values_[i]; Handle<Object> num = isolate_->factory()->NewNumber(double_value); if (trace_) { - PrintF("Materialized a new heap number %p [%e] for object\n", + PrintF("Materializing a new heap number %p [%e] for arguments object\n", reinterpret_cast<void*>(*num), double_value); } values.Set(i, num); } - // Materialize arguments/captured objects. - if (!deferred_objects_.is_empty()) { - List<Handle<Object> > materialized_objects(deferred_objects_.length()); - materialized_objects_ = &materialized_objects; - materialized_values_ = &values; - - while (materialization_object_index_ < deferred_objects_.length()) { - int object_index = materialization_object_index_; - ObjectMaterializationDescriptor descriptor = - deferred_objects_.at(object_index); - - // Find a previously materialized object by de-duplication or - // materialize a new instance of the object if necessary. Store - // the materialized object into the frame slot. - Handle<Object> object = MaterializeNextHeapObject(); - Memory::Object_at(descriptor.slot_address()) = *object; - if (trace_) { - if (descriptor.is_arguments()) { - PrintF("Materialized %sarguments object of length %d for %p: ", - ArgumentsObjectIsAdapted(object_index) ? "(adapted) " : "", - Handle<JSObject>::cast(object)->elements()->length(), - reinterpret_cast<void*>(descriptor.slot_address())); - } else { - PrintF("Materialized captured object of size %d for %p: ", - Handle<HeapObject>::cast(object)->Size(), + // Materialize arguments objects one frame at a time. + for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) { + if (frame_index != 0) it->Advance(); + JavaScriptFrame* frame = it->frame(); + Handle<JSFunction> function(frame->function(), isolate_); + Handle<JSObject> arguments; + for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) { + if (frame->GetExpression(i) == isolate_->heap()->arguments_marker()) { + ObjectMaterializationDescriptor descriptor = + deferred_objects_.RemoveLast(); + const int length = descriptor.object_length(); + if (arguments.is_null()) { + if (frame->has_adapted_arguments()) { + // Use the arguments adapter frame we just built to materialize the + // arguments object. FunctionGetArguments can't throw an exception. + arguments = Handle<JSObject>::cast( + Accessors::FunctionGetArguments(function)); + values.RewindBy(length); + } else { + // Construct an arguments object and copy the parameters to a newly + // allocated arguments object backing store. + arguments = + isolate_->factory()->NewArgumentsObject(function, length); + Handle<FixedArray> array = + isolate_->factory()->NewFixedArray(length); + ASSERT(array->length() == length); + for (int i = length - 1; i >= 0 ; --i) { + array->set(i, *values.RemoveLast()); + } + arguments->set_elements(*array); + } + } + frame->SetExpression(i, *arguments); + ASSERT_EQ(Memory::Object_at(descriptor.slot_address()), *arguments); + if (trace_) { + PrintF("Materializing %sarguments object of length %d for %p: ", + frame->has_adapted_arguments() ? "(adapted) " : "", + arguments->elements()->length(), reinterpret_cast<void*>(descriptor.slot_address())); + arguments->ShortPrint(); + PrintF("\n"); } - object->ShortPrint(); - PrintF("\n"); } } - - ASSERT(materialization_object_index_ == materialized_objects_->length()); - ASSERT(materialization_value_index_ == materialized_values_->length()); } } @@ -1874,10 +1786,10 @@ static const char* TraceValueType(bool is_smi, bool is_native = false) { void Deoptimizer::DoTranslateObject(TranslationIterator* iterator, - int object_index, + int object_opcode, int field_index) { disasm::NameConverter converter; - Address object_slot = deferred_objects_[object_index].slot_address(); + Address object_slot = deferred_objects_.last().slot_address(); Translation::Opcode opcode = static_cast<Translation::Opcode>(iterator->Next()); @@ -1890,6 +1802,7 @@ void Deoptimizer::DoTranslateObject(TranslationIterator* iterator, case Translation::GETTER_STUB_FRAME: case Translation::SETTER_STUB_FRAME: case Translation::COMPILED_STUB_FRAME: + case Translation::ARGUMENTS_OBJECT: UNREACHABLE(); return; @@ -2059,50 +1972,6 @@ void Deoptimizer::DoTranslateObject(TranslationIterator* iterator, AddObjectTaggedValue(value); return; } - - case Translation::DUPLICATED_OBJECT: { - int object_index = iterator->Next(); - if (trace_) { - PrintF(" nested @0x%08" V8PRIxPTR ": [field #%d] <- ", - reinterpret_cast<intptr_t>(object_slot), - field_index); - isolate_->heap()->arguments_marker()->ShortPrint(); - PrintF(" ; duplicate of object #%d\n", object_index); - } - // Use the materialization marker value as a sentinel and fill in - // the object after the deoptimized frame is built. - intptr_t value = reinterpret_cast<intptr_t>( - isolate_->heap()->arguments_marker()); - AddObjectDuplication(0, object_index); - AddObjectTaggedValue(value); - return; - } - - case Translation::ARGUMENTS_OBJECT: - case Translation::CAPTURED_OBJECT: { - int length = iterator->Next(); - bool is_args = opcode == Translation::ARGUMENTS_OBJECT; - if (trace_) { - PrintF(" nested @0x%08" V8PRIxPTR ": [field #%d] <- ", - reinterpret_cast<intptr_t>(object_slot), - field_index); - isolate_->heap()->arguments_marker()->ShortPrint(); - PrintF(" ; object (length = %d, is_args = %d)\n", length, is_args); - } - // Use the materialization marker value as a sentinel and fill in - // the object after the deoptimized frame is built. - intptr_t value = reinterpret_cast<intptr_t>( - isolate_->heap()->arguments_marker()); - AddObjectStart(0, length, is_args); - AddObjectTaggedValue(value); - // We save the object values on the side and materialize the actual - // object after the deoptimized frame is built. - int object_index = deferred_objects_.length() - 1; - for (int i = 0; i < length; i++) { - DoTranslateObject(iterator, object_index, i); - } - return; - } } } @@ -2342,48 +2211,25 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, return; } - case Translation::DUPLICATED_OBJECT: { - int object_index = iterator->Next(); - if (trace_) { - PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ", - output_[frame_index]->GetTop() + output_offset, - output_offset); - isolate_->heap()->arguments_marker()->ShortPrint(); - PrintF(" ; duplicate of object #%d\n", object_index); - } - // Use the materialization marker value as a sentinel and fill in - // the object after the deoptimized frame is built. - intptr_t value = reinterpret_cast<intptr_t>( - isolate_->heap()->arguments_marker()); - AddObjectDuplication(output_[frame_index]->GetTop() + output_offset, - object_index); - output_[frame_index]->SetFrameSlot(output_offset, value); - return; - } - - case Translation::ARGUMENTS_OBJECT: - case Translation::CAPTURED_OBJECT: { + case Translation::ARGUMENTS_OBJECT: { int length = iterator->Next(); - bool is_args = opcode == Translation::ARGUMENTS_OBJECT; if (trace_) { PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ", output_[frame_index]->GetTop() + output_offset, output_offset); isolate_->heap()->arguments_marker()->ShortPrint(); - PrintF(" ; object (length = %d, is_args = %d)\n", length, is_args); + PrintF(" ; arguments object (length = %d)\n", length); } - // Use the materialization marker value as a sentinel and fill in - // the object after the deoptimized frame is built. + // Use the arguments marker value as a sentinel and fill in the arguments + // object after the deoptimized frame is built. intptr_t value = reinterpret_cast<intptr_t>( isolate_->heap()->arguments_marker()); - AddObjectStart(output_[frame_index]->GetTop() + output_offset, - length, is_args); + AddObjectStart(output_[frame_index]->GetTop() + output_offset, length); output_[frame_index]->SetFrameSlot(output_offset, value); - // We save the object values on the side and materialize the actual - // object after the deoptimized frame is built. - int object_index = deferred_objects_.length() - 1; + // We save the argument values on the side and materialize the actual + // arguments object after the deoptimized frame is built. for (int i = 0; i < length; i++) { - DoTranslateObject(iterator, object_index, i); + DoTranslateObject(iterator, Translation::ARGUMENTS_OBJECT, i); } return; } @@ -2560,9 +2406,7 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator, break; } - case Translation::DUPLICATED_OBJECT: - case Translation::ARGUMENTS_OBJECT: - case Translation::CAPTURED_OBJECT: { + case Translation::ARGUMENTS_OBJECT: { // Optimized code assumes that the argument object has not been // materialized and so bypasses it when doing arguments access. // We should have bailed out before starting the frame @@ -2582,19 +2426,25 @@ void Deoptimizer::PatchInterruptCode(Code* unoptimized_code, Code* replacement_code) { // Iterate over the back edge table and patch every interrupt // call to an unconditional call to the replacement code. + ASSERT(unoptimized_code->kind() == Code::FUNCTION); int loop_nesting_level = unoptimized_code->allow_osr_at_loop_nesting_level(); - - for (FullCodeGenerator::BackEdgeTableIterator back_edges(unoptimized_code); - !back_edges.Done(); - back_edges.Next()) { - if (static_cast<int>(back_edges.loop_depth()) == loop_nesting_level) { + Address back_edge_cursor = unoptimized_code->instruction_start() + + unoptimized_code->back_edge_table_offset(); + uint32_t table_length = Memory::uint32_at(back_edge_cursor); + back_edge_cursor += kIntSize; + for (uint32_t i = 0; i < table_length; ++i) { + uint32_t loop_depth = Memory::uint32_at(back_edge_cursor + 2 * kIntSize); + if (static_cast<int>(loop_depth) == loop_nesting_level) { + // Loop back edge has the loop depth that we want to patch. + uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize); + Address pc_after = unoptimized_code->instruction_start() + pc_offset; PatchInterruptCodeAt(unoptimized_code, - back_edges.pc(), + pc_after, interrupt_code, replacement_code); } + back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize; } - unoptimized_code->set_back_edges_patched_for_osr(true); #ifdef DEBUG Deoptimizer::VerifyInterruptCode( @@ -2607,20 +2457,25 @@ void Deoptimizer::RevertInterruptCode(Code* unoptimized_code, Code* interrupt_code, Code* replacement_code) { // Iterate over the back edge table and revert the patched interrupt calls. + ASSERT(unoptimized_code->kind() == Code::FUNCTION); ASSERT(unoptimized_code->back_edges_patched_for_osr()); int loop_nesting_level = unoptimized_code->allow_osr_at_loop_nesting_level(); - - for (FullCodeGenerator::BackEdgeTableIterator back_edges(unoptimized_code); - !back_edges.Done(); - back_edges.Next()) { - if (static_cast<int>(back_edges.loop_depth()) <= loop_nesting_level) { + Address back_edge_cursor = unoptimized_code->instruction_start() + + unoptimized_code->back_edge_table_offset(); + uint32_t table_length = Memory::uint32_at(back_edge_cursor); + back_edge_cursor += kIntSize; + for (uint32_t i = 0; i < table_length; ++i) { + uint32_t loop_depth = Memory::uint32_at(back_edge_cursor + 2 * kIntSize); + if (static_cast<int>(loop_depth) <= loop_nesting_level) { + uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize); + Address pc_after = unoptimized_code->instruction_start() + pc_offset; RevertInterruptCodeAt(unoptimized_code, - back_edges.pc(), + pc_after, interrupt_code, replacement_code); } + back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize; } - unoptimized_code->set_back_edges_patched_for_osr(false); unoptimized_code->set_allow_osr_at_loop_nesting_level(0); #ifdef DEBUG @@ -2636,18 +2491,24 @@ void Deoptimizer::VerifyInterruptCode(Code* unoptimized_code, Code* interrupt_code, Code* replacement_code, int loop_nesting_level) { - for (FullCodeGenerator::BackEdgeTableIterator back_edges(unoptimized_code); - !back_edges.Done(); - back_edges.Next()) { - uint32_t loop_depth = back_edges.loop_depth(); + CHECK(unoptimized_code->kind() == Code::FUNCTION); + Address back_edge_cursor = unoptimized_code->instruction_start() + + unoptimized_code->back_edge_table_offset(); + uint32_t table_length = Memory::uint32_at(back_edge_cursor); + back_edge_cursor += kIntSize; + for (uint32_t i = 0; i < table_length; ++i) { + uint32_t loop_depth = Memory::uint32_at(back_edge_cursor + 2 * kIntSize); CHECK_LE(static_cast<int>(loop_depth), Code::kMaxLoopNestingMarker); // Assert that all back edges for shallower loops (and only those) // have already been patched. + uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize); + Address pc_after = unoptimized_code->instruction_start() + pc_offset; CHECK_EQ((static_cast<int>(loop_depth) <= loop_nesting_level), InterruptCodeIsPatched(unoptimized_code, - back_edges.pc(), + pc_after, interrupt_code, replacement_code)); + back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize; } } #endif // DEBUG @@ -2710,16 +2571,9 @@ Object* Deoptimizer::ComputeLiteral(int index) const { } -void Deoptimizer::AddObjectStart(intptr_t slot, int length, bool is_args) { +void Deoptimizer::AddObjectStart(intptr_t slot_address, int length) { ObjectMaterializationDescriptor object_desc( - reinterpret_cast<Address>(slot), jsframe_count_, length, -1, is_args); - deferred_objects_.Add(object_desc); -} - - -void Deoptimizer::AddObjectDuplication(intptr_t slot, int object_index) { - ObjectMaterializationDescriptor object_desc( - reinterpret_cast<Address>(slot), jsframe_count_, -1, object_index, false); + reinterpret_cast<Address>(slot_address), length); deferred_objects_.Add(object_desc); } @@ -2947,18 +2801,6 @@ void Translation::BeginArgumentsObject(int args_length) { } -void Translation::BeginCapturedObject(int length) { - buffer_->Add(CAPTURED_OBJECT, zone()); - buffer_->Add(length, zone()); -} - - -void Translation::DuplicateObject(int object_index) { - buffer_->Add(DUPLICATED_OBJECT, zone()); - buffer_->Add(object_index, zone()); -} - - void Translation::StoreRegister(Register reg) { buffer_->Add(REGISTER, zone()); buffer_->Add(reg.code(), zone()); @@ -3027,9 +2869,7 @@ int Translation::NumberOfOperandsFor(Opcode opcode) { switch (opcode) { case GETTER_STUB_FRAME: case SETTER_STUB_FRAME: - case DUPLICATED_OBJECT: case ARGUMENTS_OBJECT: - case CAPTURED_OBJECT: case REGISTER: case INT32_REGISTER: case UINT32_REGISTER: @@ -3089,12 +2929,8 @@ const char* Translation::StringFor(Opcode opcode) { return "DOUBLE_STACK_SLOT"; case LITERAL: return "LITERAL"; - case DUPLICATED_OBJECT: - return "DUPLICATED_OBJECT"; case ARGUMENTS_OBJECT: return "ARGUMENTS_OBJECT"; - case CAPTURED_OBJECT: - return "CAPTURED_OBJECT"; } UNREACHABLE(); return ""; @@ -3138,9 +2974,7 @@ SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator, // Peeled off before getting here. break; - case Translation::DUPLICATED_OBJECT: case Translation::ARGUMENTS_OBJECT: - case Translation::CAPTURED_OBJECT: // This can be only emitted for local slots not for argument slots. break; diff --git a/chromium/v8/src/deoptimizer.h b/chromium/v8/src/deoptimizer.h index b6e4667a20d..7ad1ab0b2e7 100644 --- a/chromium/v8/src/deoptimizer.h +++ b/chromium/v8/src/deoptimizer.h @@ -77,31 +77,15 @@ class HeapNumberMaterializationDescriptor BASE_EMBEDDED { class ObjectMaterializationDescriptor BASE_EMBEDDED { public: - ObjectMaterializationDescriptor( - Address slot_address, int frame, int length, int duplicate, bool is_args) - : slot_address_(slot_address), - jsframe_index_(frame), - object_length_(length), - duplicate_object_(duplicate), - is_arguments_(is_args) { } + ObjectMaterializationDescriptor(Address slot_address, int length) + : slot_address_(slot_address), object_length_(length) { } Address slot_address() const { return slot_address_; } - int jsframe_index() const { return jsframe_index_; } int object_length() const { return object_length_; } - int duplicate_object() const { return duplicate_object_; } - bool is_arguments() const { return is_arguments_; } - - // Only used for allocated receivers in DoComputeConstructStubFrame. - void patch_slot_address(intptr_t slot) { - slot_address_ = reinterpret_cast<Address>(slot); - } private: Address slot_address_; - int jsframe_index_; int object_length_; - int duplicate_object_; - bool is_arguments_; }; @@ -388,7 +372,7 @@ class Deoptimizer : public Malloced { int frame_index); void DoTranslateObject(TranslationIterator* iterator, - int object_index, + int object_opcode, int field_index); enum DeoptimizerTranslatedValueType { @@ -416,28 +400,11 @@ class Deoptimizer : public Malloced { Object* ComputeLiteral(int index) const; - void AddObjectStart(intptr_t slot_address, int argc, bool is_arguments); - void AddObjectDuplication(intptr_t slot, int object_index); + void AddObjectStart(intptr_t slot_address, int argc); void AddObjectTaggedValue(intptr_t value); void AddObjectDoubleValue(double value); void AddDoubleValue(intptr_t slot_address, double value); - bool ArgumentsObjectIsAdapted(int object_index) { - ObjectMaterializationDescriptor desc = deferred_objects_.at(object_index); - int reverse_jsframe_index = jsframe_count_ - desc.jsframe_index() - 1; - return jsframe_has_adapted_arguments_[reverse_jsframe_index]; - } - - Handle<JSFunction> ArgumentsObjectFunction(int object_index) { - ObjectMaterializationDescriptor desc = deferred_objects_.at(object_index); - int reverse_jsframe_index = jsframe_count_ - desc.jsframe_index() - 1; - return jsframe_functions_[reverse_jsframe_index]; - } - - // Helper function for heap object materialization. - Handle<Object> MaterializeNextHeapObject(); - Handle<Object> MaterializeNextValue(); - static void GenerateDeoptimizationEntries( MacroAssembler* masm, int count, BailoutType type); @@ -488,22 +455,10 @@ class Deoptimizer : public Malloced { // Array of output frame descriptions. FrameDescription** output_; - // Deferred values to be materialized. List<Object*> deferred_objects_tagged_values_; List<double> deferred_objects_double_values_; List<ObjectMaterializationDescriptor> deferred_objects_; List<HeapNumberMaterializationDescriptor> deferred_heap_numbers_; - - // Output frame information. Only used during heap object materialization. - List<Handle<JSFunction> > jsframe_functions_; - List<bool> jsframe_has_adapted_arguments_; - - // Materialized objects. Only used during heap object materialization. - List<Handle<Object> >* materialized_values_; - List<Handle<Object> >* materialized_objects_; - int materialization_value_index_; - int materialization_object_index_; - #ifdef DEBUG DisallowHeapAllocation* disallow_heap_allocation_; #endif // DEBUG @@ -757,9 +712,7 @@ class Translation BASE_EMBEDDED { SETTER_STUB_FRAME, ARGUMENTS_ADAPTOR_FRAME, COMPILED_STUB_FRAME, - DUPLICATED_OBJECT, ARGUMENTS_OBJECT, - CAPTURED_OBJECT, REGISTER, INT32_REGISTER, UINT32_REGISTER, @@ -791,8 +744,6 @@ class Translation BASE_EMBEDDED { void BeginGetterStubFrame(int literal_id); void BeginSetterStubFrame(int literal_id); void BeginArgumentsObject(int args_length); - void BeginCapturedObject(int length); - void DuplicateObject(int object_index); void StoreRegister(Register reg); void StoreInt32Register(Register reg); void StoreUint32Register(Register reg); diff --git a/chromium/v8/src/effects.h b/chromium/v8/src/effects.h deleted file mode 100644 index 8e823634710..00000000000 --- a/chromium/v8/src/effects.h +++ /dev/null @@ -1,361 +0,0 @@ -// Copyright 2013 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_EFFECTS_H_ -#define V8_EFFECTS_H_ - -#include "v8.h" - -#include "types.h" - -namespace v8 { -namespace internal { - - -// A simple struct to represent (write) effects. A write is represented as a -// modification of type bounds (e.g. of a variable). -// -// An effect can either be definite, if the write is known to have taken place, -// or 'possible', if it was optional. The difference is relevant when composing -// effects. -// -// There are two ways to compose effects: sequentially (they happen one after -// the other) or alternatively (either one or the other happens). A definite -// effect cancels out any previous effect upon sequencing. A possible effect -// merges into a previous effect, i.e., type bounds are merged. Alternative -// composition always merges bounds. It yields a possible effect if at least -// one was only possible. -struct Effect { - enum Modality { POSSIBLE, DEFINITE }; - - Modality modality; - Bounds bounds; - - Effect() {} - Effect(Bounds b, Modality m = DEFINITE) : modality(m), bounds(b) {} - - // The unknown effect. - static Effect Unknown(Isolate* isolate) { - return Effect(Bounds::Unbounded(isolate), POSSIBLE); - } - - static Effect Forget(Isolate* isolate) { - return Effect(Bounds::Unbounded(isolate), DEFINITE); - } - - // Sequential composition, as in 'e1; e2'. - static Effect Seq(Effect e1, Effect e2, Isolate* isolate) { - if (e2.modality == DEFINITE) return e2; - return Effect(Bounds::Either(e1.bounds, e2.bounds, isolate), e1.modality); - } - - // Alternative composition, as in 'cond ? e1 : e2'. - static Effect Alt(Effect e1, Effect e2, Isolate* isolate) { - return Effect( - Bounds::Either(e1.bounds, e2.bounds, isolate), - e1.modality == POSSIBLE ? POSSIBLE : e2.modality); - } -}; - - -// Classes encapsulating sets of effects on variables. -// -// Effects maps variables to effects and supports sequential and alternative -// composition. -// -// NestedEffects is an incremental representation that supports persistence -// through functional extension. It represents the map as an adjoin of a list -// of maps, whose tail can be shared. -// -// Both classes provide similar interfaces, implemented in parts through the -// EffectsMixin below (using sandwich style, to work around the style guide's -// MI restriction). -// -// We also (ab)use Effects/NestedEffects as a representation for abstract -// store typings. In that case, only definite effects are of interest. - -template<class Var, class Base, class Effects> -class EffectsMixin: public Base { - public: - explicit EffectsMixin(Zone* zone) : Base(zone) {} - - Effect Lookup(Var var) { - Locator locator; - return this->Find(var, &locator) - ? locator.value() : Effect::Unknown(Base::isolate()); - } - - Bounds LookupBounds(Var var) { - Effect effect = Lookup(var); - return effect.modality == Effect::DEFINITE - ? effect.bounds : Bounds::Unbounded(Base::isolate()); - } - - // Sequential composition. - void Seq(Var var, Effect effect) { - Locator locator; - if (!this->Insert(var, &locator)) { - effect = Effect::Seq(locator.value(), effect, Base::isolate()); - } - locator.set_value(effect); - } - - void Seq(Effects that) { - SeqMerger<EffectsMixin> merge = { *this }; - that.ForEach(&merge); - } - - // Alternative composition. - void Alt(Var var, Effect effect) { - Locator locator; - if (!this->Insert(var, &locator)) { - effect = Effect::Alt(locator.value(), effect, Base::isolate()); - } - locator.set_value(effect); - } - - void Alt(Effects that) { - AltWeakener<EffectsMixin> weaken = { *this, that }; - this->ForEach(&weaken); - AltMerger<EffectsMixin> merge = { *this }; - that.ForEach(&merge); - } - - // Invalidation. - void Forget() { - Overrider override = { - Effect::Forget(Base::isolate()), Effects(Base::zone()) }; - this->ForEach(&override); - Seq(override.effects); - } - - protected: - typedef typename Base::Locator Locator; - - template<class Self> - struct SeqMerger { - void Call(Var var, Effect effect) { self.Seq(var, effect); } - Self self; - }; - - template<class Self> - struct AltMerger { - void Call(Var var, Effect effect) { self.Alt(var, effect); } - Self self; - }; - - template<class Self> - struct AltWeakener { - void Call(Var var, Effect effect) { - if (effect.modality == Effect::DEFINITE && !other.Contains(var)) { - effect.modality = Effect::POSSIBLE; - Locator locator; - self.Insert(var, &locator); - locator.set_value(effect); - } - } - Self self; - Effects other; - }; - - struct Overrider { - void Call(Var var, Effect effect) { effects.Seq(var, new_effect); } - Effect new_effect; - Effects effects; - }; -}; - - -template<class Var, Var kNoVar> class Effects; -template<class Var, Var kNoVar> class NestedEffectsBase; - -template<class Var, Var kNoVar> -class EffectsBase { - public: - explicit EffectsBase(Zone* zone) : map_(new(zone) Mapping(zone)) {} - - bool IsEmpty() { return map_->is_empty(); } - - protected: - friend class NestedEffectsBase<Var, kNoVar>; - friend class - EffectsMixin<Var, NestedEffectsBase<Var, kNoVar>, Effects<Var, kNoVar> >; - - Zone* zone() { return map_->allocator().zone(); } - Isolate* isolate() { return zone()->isolate(); } - - struct SplayTreeConfig { - typedef Var Key; - typedef Effect Value; - static const Var kNoKey = kNoVar; - static Effect NoValue() { return Effect(); } - static int Compare(int x, int y) { return y - x; } - }; - typedef ZoneSplayTree<SplayTreeConfig> Mapping; - typedef typename Mapping::Locator Locator; - - bool Contains(Var var) { - ASSERT(var != kNoVar); - return map_->Contains(var); - } - bool Find(Var var, Locator* locator) { - ASSERT(var != kNoVar); - return map_->Find(var, locator); - } - bool Insert(Var var, Locator* locator) { - ASSERT(var != kNoVar); - return map_->Insert(var, locator); - } - - template<class Callback> - void ForEach(Callback* callback) { - return map_->ForEach(callback); - } - - private: - Mapping* map_; -}; - -template<class Var, Var kNoVar> -const Var EffectsBase<Var, kNoVar>::SplayTreeConfig::kNoKey; - -template<class Var, Var kNoVar> -class Effects: public - EffectsMixin<Var, EffectsBase<Var, kNoVar>, Effects<Var, kNoVar> > { - public: - explicit Effects(Zone* zone) - : EffectsMixin<Var, EffectsBase<Var, kNoVar>, Effects<Var, kNoVar> >(zone) - {} -}; - - -template<class Var, Var kNoVar> -class NestedEffectsBase { - public: - explicit NestedEffectsBase(Zone* zone) : node_(new(zone) Node(zone)) {} - - template<class Callback> - void ForEach(Callback* callback) { - if (node_->previous) NestedEffectsBase(node_->previous).ForEach(callback); - node_->effects.ForEach(callback); - } - - Effects<Var, kNoVar> Top() { return node_->effects; } - - bool IsEmpty() { - for (Node* node = node_; node != NULL; node = node->previous) { - if (!node->effects.IsEmpty()) return false; - } - return true; - } - - protected: - typedef typename EffectsBase<Var, kNoVar>::Locator Locator; - - Zone* zone() { return node_->zone; } - Isolate* isolate() { return zone()->isolate(); } - - void push() { node_ = new(node_->zone) Node(node_->zone, node_); } - void pop() { node_ = node_->previous; } - bool is_empty() { return node_ == NULL; } - - bool Contains(Var var) { - ASSERT(var != kNoVar); - for (Node* node = node_; node != NULL; node = node->previous) { - if (node->effects.Contains(var)) return true; - } - return false; - } - - bool Find(Var var, Locator* locator) { - ASSERT(var != kNoVar); - for (Node* node = node_; node != NULL; node = node->previous) { - if (node->effects.Find(var, locator)) return true; - } - return false; - } - - bool Insert(Var var, Locator* locator); - - private: - struct Node: ZoneObject { - Zone* zone; - Effects<Var, kNoVar> effects; - Node* previous; - explicit Node(Zone* zone, Node* previous = NULL) - : zone(zone), effects(zone), previous(previous) {} - }; - - explicit NestedEffectsBase(Node* node) : node_(node) {} - - Node* node_; -}; - - -template<class Var, Var kNoVar> -bool NestedEffectsBase<Var, kNoVar>::Insert(Var var, Locator* locator) { - ASSERT(var != kNoVar); - if (!node_->effects.Insert(var, locator)) return false; - Locator shadowed; - for (Node* node = node_->previous; node != NULL; node = node->previous) { - if (node->effects.Find(var, &shadowed)) { - // Initialize with shadowed entry. - locator->set_value(shadowed.value()); - return false; - } - } - return true; -} - - -template<class Var, Var kNoVar> -class NestedEffects: public - EffectsMixin<Var, NestedEffectsBase<Var, kNoVar>, Effects<Var, kNoVar> > { - public: - explicit NestedEffects(Zone* zone) : - EffectsMixin<Var, NestedEffectsBase<Var, kNoVar>, Effects<Var, kNoVar> >( - zone) {} - - // Create an extension of the current effect set. The current set should not - // be modified while the extension is in use. - NestedEffects Push() { - NestedEffects result = *this; - result.push(); - return result; - } - - NestedEffects Pop() { - NestedEffects result = *this; - result.pop(); - ASSERT(!this->is_empty()); - return result; - } -}; - -} } // namespace v8::internal - -#endif // V8_EFFECTS_H_ diff --git a/chromium/v8/src/execution.cc b/chromium/v8/src/execution.cc index ecfa1db1ed8..d7b9cf5d596 100644 --- a/chromium/v8/src/execution.cc +++ b/chromium/v8/src/execution.cc @@ -206,12 +206,10 @@ Handle<Object> Execution::TryCall(Handle<JSFunction> func, catcher.SetCaptureMessage(false); *caught_exception = false; - // Get isolate now, because handle might be persistent - // and get destroyed in the next call. - Isolate* isolate = func->GetIsolate(); Handle<Object> result = Invoke(false, func, receiver, argc, args, caught_exception); + Isolate* isolate = func->GetIsolate(); if (*caught_exception) { ASSERT(catcher.HasCaught()); ASSERT(isolate->has_pending_exception()); diff --git a/chromium/v8/src/extensions/i18n/collator.cc b/chromium/v8/src/extensions/i18n/collator.cc new file mode 100644 index 00000000000..61b1d63e5c2 --- /dev/null +++ b/chromium/v8/src/extensions/i18n/collator.cc @@ -0,0 +1,366 @@ +// Copyright 2013 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. +// limitations under the License. + +#include "collator.h" + +#include "i18n-utils.h" +#include "unicode/coll.h" +#include "unicode/locid.h" +#include "unicode/ucol.h" + +namespace v8_i18n { + +static icu::Collator* InitializeCollator( + v8::Handle<v8::String>, v8::Handle<v8::Object>, v8::Handle<v8::Object>); + +static icu::Collator* CreateICUCollator( + const icu::Locale&, v8::Handle<v8::Object>); + +static bool SetBooleanAttribute( + UColAttribute, const char*, v8::Handle<v8::Object>, icu::Collator*); + +static void SetResolvedSettings( + const icu::Locale&, icu::Collator*, v8::Handle<v8::Object>); + +static void SetBooleanSetting( + UColAttribute, icu::Collator*, const char*, v8::Handle<v8::Object>); + +icu::Collator* Collator::UnpackCollator(v8::Handle<v8::Object> obj) { + v8::HandleScope handle_scope; + + if (obj->HasOwnProperty(v8::String::New("collator"))) { + return static_cast<icu::Collator*>( + obj->GetAlignedPointerFromInternalField(0)); + } + + return NULL; +} + +void Collator::DeleteCollator(v8::Isolate* isolate, + v8::Persistent<v8::Object>* object, + void* param) { + // First delete the hidden C++ object. + // Unpacking should never return NULL here. That would only happen if + // this method is used as the weak callback for persistent handles not + // pointing to a collator. + v8::HandleScope handle_scope(isolate); + v8::Local<v8::Object> handle = v8::Local<v8::Object>::New(isolate, *object); + delete UnpackCollator(handle); + + // Then dispose of the persistent handle to JS object. + object->Dispose(isolate); +} + + +// Throws a JavaScript exception. +static v8::Handle<v8::Value> ThrowUnexpectedObjectError() { + // Returns undefined, and schedules an exception to be thrown. + return v8::ThrowException(v8::Exception::Error( + v8::String::New("Collator method called on an object " + "that is not a Collator."))); +} + + +// When there's an ICU error, throw a JavaScript error with |message|. +static v8::Handle<v8::Value> ThrowExceptionForICUError(const char* message) { + return v8::ThrowException(v8::Exception::Error(v8::String::New(message))); +} + + +// static +void Collator::JSInternalCompare( + const v8::FunctionCallbackInfo<v8::Value>& args) { + if (args.Length() != 3 || !args[0]->IsObject() || + !args[1]->IsString() || !args[2]->IsString()) { + v8::ThrowException(v8::Exception::SyntaxError( + v8::String::New("Collator and two string arguments are required."))); + return; + } + + icu::Collator* collator = UnpackCollator(args[0]->ToObject()); + if (!collator) { + ThrowUnexpectedObjectError(); + return; + } + + v8::String::Value string_value1(args[1]); + v8::String::Value string_value2(args[2]); + const UChar* string1 = reinterpret_cast<const UChar*>(*string_value1); + const UChar* string2 = reinterpret_cast<const UChar*>(*string_value2); + UErrorCode status = U_ZERO_ERROR; + UCollationResult result = collator->compare( + string1, string_value1.length(), string2, string_value2.length(), status); + + if (U_FAILURE(status)) { + ThrowExceptionForICUError( + "Internal error. Unexpected failure in Collator.compare."); + return; + } + + args.GetReturnValue().Set(result); +} + +void Collator::JSCreateCollator( + const v8::FunctionCallbackInfo<v8::Value>& args) { + if (args.Length() != 3 || !args[0]->IsString() || !args[1]->IsObject() || + !args[2]->IsObject()) { + v8::ThrowException(v8::Exception::SyntaxError( + v8::String::New("Internal error, wrong parameters."))); + return; + } + + v8::Isolate* isolate = args.GetIsolate(); + v8::Local<v8::ObjectTemplate> intl_collator_template = + Utils::GetTemplate(isolate); + + // Create an empty object wrapper. + v8::Local<v8::Object> local_object = intl_collator_template->NewInstance(); + // But the handle shouldn't be empty. + // That can happen if there was a stack overflow when creating the object. + if (local_object.IsEmpty()) { + args.GetReturnValue().Set(local_object); + return; + } + + // Set collator as internal field of the resulting JS object. + icu::Collator* collator = InitializeCollator( + args[0]->ToString(), args[1]->ToObject(), args[2]->ToObject()); + + if (!collator) { + v8::ThrowException(v8::Exception::Error(v8::String::New( + "Internal error. Couldn't create ICU collator."))); + return; + } else { + local_object->SetAlignedPointerInInternalField(0, collator); + + // Make it safer to unpack later on. + v8::TryCatch try_catch; + local_object->Set(v8::String::New("collator"), v8::String::New("valid")); + if (try_catch.HasCaught()) { + v8::ThrowException(v8::Exception::Error( + v8::String::New("Internal error, couldn't set property."))); + return; + } + } + + v8::Persistent<v8::Object> wrapper(isolate, local_object); + // Make object handle weak so we can delete iterator once GC kicks in. + wrapper.MakeWeak<void>(NULL, &DeleteCollator); + args.GetReturnValue().Set(wrapper); + wrapper.ClearAndLeak(); +} + +static icu::Collator* InitializeCollator(v8::Handle<v8::String> locale, + v8::Handle<v8::Object> options, + v8::Handle<v8::Object> resolved) { + // Convert BCP47 into ICU locale format. + UErrorCode status = U_ZERO_ERROR; + icu::Locale icu_locale; + char icu_result[ULOC_FULLNAME_CAPACITY]; + int icu_length = 0; + v8::String::AsciiValue bcp47_locale(locale); + if (bcp47_locale.length() != 0) { + uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY, + &icu_length, &status); + if (U_FAILURE(status) || icu_length == 0) { + return NULL; + } + icu_locale = icu::Locale(icu_result); + } + + icu::Collator* collator = CreateICUCollator(icu_locale, options); + if (!collator) { + // Remove extensions and try again. + icu::Locale no_extension_locale(icu_locale.getBaseName()); + collator = CreateICUCollator(no_extension_locale, options); + + // Set resolved settings (pattern, numbering system). + SetResolvedSettings(no_extension_locale, collator, resolved); + } else { + SetResolvedSettings(icu_locale, collator, resolved); + } + + return collator; +} + +static icu::Collator* CreateICUCollator( + const icu::Locale& icu_locale, v8::Handle<v8::Object> options) { + // Make collator from options. + icu::Collator* collator = NULL; + UErrorCode status = U_ZERO_ERROR; + collator = icu::Collator::createInstance(icu_locale, status); + + if (U_FAILURE(status)) { + delete collator; + return NULL; + } + + // Set flags first, and then override them with sensitivity if necessary. + SetBooleanAttribute(UCOL_NUMERIC_COLLATION, "numeric", options, collator); + + // Normalization is always on, by the spec. We are free to optimize + // if the strings are already normalized (but we don't have a way to tell + // that right now). + collator->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status); + + icu::UnicodeString case_first; + if (Utils::ExtractStringSetting(options, "caseFirst", &case_first)) { + if (case_first == UNICODE_STRING_SIMPLE("upper")) { + collator->setAttribute(UCOL_CASE_FIRST, UCOL_UPPER_FIRST, status); + } else if (case_first == UNICODE_STRING_SIMPLE("lower")) { + collator->setAttribute(UCOL_CASE_FIRST, UCOL_LOWER_FIRST, status); + } else { + // Default (false/off). + collator->setAttribute(UCOL_CASE_FIRST, UCOL_OFF, status); + } + } + + icu::UnicodeString sensitivity; + if (Utils::ExtractStringSetting(options, "sensitivity", &sensitivity)) { + if (sensitivity == UNICODE_STRING_SIMPLE("base")) { + collator->setStrength(icu::Collator::PRIMARY); + } else if (sensitivity == UNICODE_STRING_SIMPLE("accent")) { + collator->setStrength(icu::Collator::SECONDARY); + } else if (sensitivity == UNICODE_STRING_SIMPLE("case")) { + collator->setStrength(icu::Collator::PRIMARY); + collator->setAttribute(UCOL_CASE_LEVEL, UCOL_ON, status); + } else { + // variant (default) + collator->setStrength(icu::Collator::TERTIARY); + } + } + + bool ignore; + if (Utils::ExtractBooleanSetting(options, "ignorePunctuation", &ignore)) { + if (ignore) { + collator->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, status); + } + } + + return collator; +} + +static bool SetBooleanAttribute(UColAttribute attribute, + const char* name, + v8::Handle<v8::Object> options, + icu::Collator* collator) { + UErrorCode status = U_ZERO_ERROR; + bool result; + if (Utils::ExtractBooleanSetting(options, name, &result)) { + collator->setAttribute(attribute, result ? UCOL_ON : UCOL_OFF, status); + if (U_FAILURE(status)) { + return false; + } + } + + return true; +} + +static void SetResolvedSettings(const icu::Locale& icu_locale, + icu::Collator* collator, + v8::Handle<v8::Object> resolved) { + SetBooleanSetting(UCOL_NUMERIC_COLLATION, collator, "numeric", resolved); + + UErrorCode status = U_ZERO_ERROR; + + switch (collator->getAttribute(UCOL_CASE_FIRST, status)) { + case UCOL_LOWER_FIRST: + resolved->Set(v8::String::New("caseFirst"), v8::String::New("lower")); + break; + case UCOL_UPPER_FIRST: + resolved->Set(v8::String::New("caseFirst"), v8::String::New("upper")); + break; + default: + resolved->Set(v8::String::New("caseFirst"), v8::String::New("false")); + } + + switch (collator->getAttribute(UCOL_STRENGTH, status)) { + case UCOL_PRIMARY: { + resolved->Set(v8::String::New("strength"), v8::String::New("primary")); + + // case level: true + s1 -> case, s1 -> base. + if (UCOL_ON == collator->getAttribute(UCOL_CASE_LEVEL, status)) { + resolved->Set(v8::String::New("sensitivity"), v8::String::New("case")); + } else { + resolved->Set(v8::String::New("sensitivity"), v8::String::New("base")); + } + break; + } + case UCOL_SECONDARY: + resolved->Set(v8::String::New("strength"), v8::String::New("secondary")); + resolved->Set(v8::String::New("sensitivity"), v8::String::New("accent")); + break; + case UCOL_TERTIARY: + resolved->Set(v8::String::New("strength"), v8::String::New("tertiary")); + resolved->Set(v8::String::New("sensitivity"), v8::String::New("variant")); + break; + case UCOL_QUATERNARY: + // We shouldn't get quaternary and identical from ICU, but if we do + // put them into variant. + resolved->Set(v8::String::New("strength"), v8::String::New("quaternary")); + resolved->Set(v8::String::New("sensitivity"), v8::String::New("variant")); + break; + default: + resolved->Set(v8::String::New("strength"), v8::String::New("identical")); + resolved->Set(v8::String::New("sensitivity"), v8::String::New("variant")); + } + + if (UCOL_SHIFTED == collator->getAttribute(UCOL_ALTERNATE_HANDLING, status)) { + resolved->Set(v8::String::New("ignorePunctuation"), + v8::Boolean::New(true)); + } else { + resolved->Set(v8::String::New("ignorePunctuation"), + v8::Boolean::New(false)); + } + + // Set the locale + char result[ULOC_FULLNAME_CAPACITY]; + status = U_ZERO_ERROR; + uloc_toLanguageTag( + icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status); + if (U_SUCCESS(status)) { + resolved->Set(v8::String::New("locale"), v8::String::New(result)); + } else { + // This would never happen, since we got the locale from ICU. + resolved->Set(v8::String::New("locale"), v8::String::New("und")); + } +} + +static void SetBooleanSetting(UColAttribute attribute, + icu::Collator* collator, + const char* property, + v8::Handle<v8::Object> resolved) { + UErrorCode status = U_ZERO_ERROR; + if (UCOL_ON == collator->getAttribute(attribute, status)) { + resolved->Set(v8::String::New(property), v8::Boolean::New(true)); + } else { + resolved->Set(v8::String::New(property), v8::Boolean::New(false)); + } +} + +} // namespace v8_i18n diff --git a/chromium/v8/src/extensions/i18n/collator.h b/chromium/v8/src/extensions/i18n/collator.h new file mode 100644 index 00000000000..a3991b9ed24 --- /dev/null +++ b/chromium/v8/src/extensions/i18n/collator.h @@ -0,0 +1,68 @@ +// Copyright 2013 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. +// limitations under the License. + +#ifndef V8_EXTENSIONS_I18N_COLLATOR_H_ +#define V8_EXTENSIONS_I18N_COLLATOR_H_ + +#include "unicode/uversion.h" +#include "v8.h" + +namespace U_ICU_NAMESPACE { +class Collator; +class UnicodeString; +} + +namespace v8_i18n { + +class Collator { + public: + static void JSCreateCollator(const v8::FunctionCallbackInfo<v8::Value>& args); + + // Helper methods for various bindings. + + // Unpacks collator object from corresponding JavaScript object. + static icu::Collator* UnpackCollator(v8::Handle<v8::Object> obj); + + // Release memory we allocated for the Collator once the JS object that + // holds the pointer gets garbage collected. + static void DeleteCollator(v8::Isolate* isolate, + v8::Persistent<v8::Object>* object, + void* param); + + // Compare two strings and returns -1, 0 and 1 depending on + // whether string1 is smaller than, equal to or larger than string2. + static void JSInternalCompare( + const v8::FunctionCallbackInfo<v8::Value>& args); + + private: + Collator() {} +}; + +} // namespace v8_i18n + +#endif // V8_EXTENSIONS_I18N_COLLATOR_H_ diff --git a/chromium/v8/src/extensions/i18n/collator.js b/chromium/v8/src/extensions/i18n/collator.js index d8d247b36f4..3483515bef2 100644 --- a/chromium/v8/src/extensions/i18n/collator.js +++ b/chromium/v8/src/extensions/i18n/collator.js @@ -35,6 +35,8 @@ * Useful for subclassing. */ function initializeCollator(collator, locales, options) { + native function NativeJSCreateCollator(); + if (collator.hasOwnProperty('__initializedIntlObject')) { throw new TypeError('Trying to re-initialize Collator object.'); } @@ -101,9 +103,9 @@ function initializeCollator(collator, locales, options) { usage: {value: internalOptions.usage, writable: true} }); - var internalCollator = %CreateCollator(requestedLocale, - internalOptions, - resolved); + var internalCollator = NativeJSCreateCollator(requestedLocale, + internalOptions, + resolved); // Writable, configurable and enumerable are set to false by default. Object.defineProperty(collator, 'collator', {value: internalCollator}); @@ -202,7 +204,8 @@ function initializeCollator(collator, locales, options) { * the sort order, or x comes after y in the sort order, respectively. */ function compare(collator, x, y) { - return %InternalCompare(collator.collator, String(x), String(y)); + native function NativeJSInternalCompare(); + return NativeJSInternalCompare(collator.collator, String(x), String(y)); }; diff --git a/chromium/v8/src/extensions/i18n/date-format.cc b/chromium/v8/src/extensions/i18n/date-format.cc new file mode 100644 index 00000000000..1058e37a58c --- /dev/null +++ b/chromium/v8/src/extensions/i18n/date-format.cc @@ -0,0 +1,329 @@ +// Copyright 2013 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. +// limitations under the License. + +#include "date-format.h" + +#include <string.h> + +#include "i18n-utils.h" +#include "unicode/calendar.h" +#include "unicode/dtfmtsym.h" +#include "unicode/dtptngen.h" +#include "unicode/locid.h" +#include "unicode/numsys.h" +#include "unicode/smpdtfmt.h" +#include "unicode/timezone.h" + +namespace v8_i18n { + +static icu::SimpleDateFormat* InitializeDateTimeFormat(v8::Handle<v8::String>, + v8::Handle<v8::Object>, + v8::Handle<v8::Object>); +static icu::SimpleDateFormat* CreateICUDateFormat(const icu::Locale&, + v8::Handle<v8::Object>); +static void SetResolvedSettings(const icu::Locale&, + icu::SimpleDateFormat*, + v8::Handle<v8::Object>); + +icu::SimpleDateFormat* DateFormat::UnpackDateFormat( + v8::Handle<v8::Object> obj) { + v8::HandleScope handle_scope; + + if (obj->HasOwnProperty(v8::String::New("dateFormat"))) { + return static_cast<icu::SimpleDateFormat*>( + obj->GetAlignedPointerFromInternalField(0)); + } + + return NULL; +} + +void DateFormat::DeleteDateFormat(v8::Isolate* isolate, + v8::Persistent<v8::Object>* object, + void* param) { + // First delete the hidden C++ object. + // Unpacking should never return NULL here. That would only happen if + // this method is used as the weak callback for persistent handles not + // pointing to a date time formatter. + v8::HandleScope handle_scope(isolate); + v8::Local<v8::Object> handle = v8::Local<v8::Object>::New(isolate, *object); + delete UnpackDateFormat(handle); + + // Then dispose of the persistent handle to JS object. + object->Dispose(isolate); +} + +void DateFormat::JSInternalFormat( + const v8::FunctionCallbackInfo<v8::Value>& args) { + double millis = 0.0; + if (args.Length() != 2 || !args[0]->IsObject() || !args[1]->IsDate()) { + v8::ThrowException(v8::Exception::Error( + v8::String::New( + "Internal error. Formatter and date value have to be specified."))); + return; + } else { + millis = v8::Date::Cast(*args[1])->NumberValue(); + } + + icu::SimpleDateFormat* date_format = UnpackDateFormat(args[0]->ToObject()); + if (!date_format) { + v8::ThrowException(v8::Exception::Error( + v8::String::New("DateTimeFormat method called on an object " + "that is not a DateTimeFormat."))); + return; + } + + icu::UnicodeString result; + date_format->format(millis, result); + + args.GetReturnValue().Set(v8::String::New( + reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length())); +} + +void DateFormat::JSInternalParse( + const v8::FunctionCallbackInfo<v8::Value>& args) { + icu::UnicodeString string_date; + if (args.Length() != 2 || !args[0]->IsObject() || !args[1]->IsString()) { + v8::ThrowException(v8::Exception::Error( + v8::String::New( + "Internal error. Formatter and string have to be specified."))); + return; + } else { + if (!Utils::V8StringToUnicodeString(args[1], &string_date)) { + string_date = ""; + } + } + + icu::SimpleDateFormat* date_format = UnpackDateFormat(args[0]->ToObject()); + if (!date_format) { + v8::ThrowException(v8::Exception::Error( + v8::String::New("DateTimeFormat method called on an object " + "that is not a DateTimeFormat."))); + return; + } + + UErrorCode status = U_ZERO_ERROR; + UDate date = date_format->parse(string_date, status); + if (U_FAILURE(status)) { + return; + } + + args.GetReturnValue().Set(v8::Date::New(static_cast<double>(date))); +} + +void DateFormat::JSCreateDateTimeFormat( + const v8::FunctionCallbackInfo<v8::Value>& args) { + if (args.Length() != 3 || + !args[0]->IsString() || + !args[1]->IsObject() || + !args[2]->IsObject()) { + v8::ThrowException(v8::Exception::Error( + v8::String::New("Internal error, wrong parameters."))); + return; + } + + v8::Isolate* isolate = args.GetIsolate(); + v8::Local<v8::ObjectTemplate> date_format_template = + Utils::GetTemplate(isolate); + + // Create an empty object wrapper. + v8::Local<v8::Object> local_object = date_format_template->NewInstance(); + // But the handle shouldn't be empty. + // That can happen if there was a stack overflow when creating the object. + if (local_object.IsEmpty()) { + args.GetReturnValue().Set(local_object); + return; + } + + // Set date time formatter as internal field of the resulting JS object. + icu::SimpleDateFormat* date_format = InitializeDateTimeFormat( + args[0]->ToString(), args[1]->ToObject(), args[2]->ToObject()); + + if (!date_format) { + v8::ThrowException(v8::Exception::Error(v8::String::New( + "Internal error. Couldn't create ICU date time formatter."))); + return; + } else { + local_object->SetAlignedPointerInInternalField(0, date_format); + + v8::TryCatch try_catch; + local_object->Set(v8::String::New("dateFormat"), v8::String::New("valid")); + if (try_catch.HasCaught()) { + v8::ThrowException(v8::Exception::Error( + v8::String::New("Internal error, couldn't set property."))); + return; + } + } + + v8::Persistent<v8::Object> wrapper(isolate, local_object); + // Make object handle weak so we can delete iterator once GC kicks in. + wrapper.MakeWeak<void>(NULL, &DeleteDateFormat); + args.GetReturnValue().Set(wrapper); + wrapper.ClearAndLeak(); +} + +static icu::SimpleDateFormat* InitializeDateTimeFormat( + v8::Handle<v8::String> locale, + v8::Handle<v8::Object> options, + v8::Handle<v8::Object> resolved) { + // Convert BCP47 into ICU locale format. + UErrorCode status = U_ZERO_ERROR; + icu::Locale icu_locale; + char icu_result[ULOC_FULLNAME_CAPACITY]; + int icu_length = 0; + v8::String::AsciiValue bcp47_locale(locale); + if (bcp47_locale.length() != 0) { + uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY, + &icu_length, &status); + if (U_FAILURE(status) || icu_length == 0) { + return NULL; + } + icu_locale = icu::Locale(icu_result); + } + + icu::SimpleDateFormat* date_format = CreateICUDateFormat(icu_locale, options); + if (!date_format) { + // Remove extensions and try again. + icu::Locale no_extension_locale(icu_locale.getBaseName()); + date_format = CreateICUDateFormat(no_extension_locale, options); + + // Set resolved settings (pattern, numbering system, calendar). + SetResolvedSettings(no_extension_locale, date_format, resolved); + } else { + SetResolvedSettings(icu_locale, date_format, resolved); + } + + return date_format; +} + +static icu::SimpleDateFormat* CreateICUDateFormat( + const icu::Locale& icu_locale, v8::Handle<v8::Object> options) { + // Create time zone as specified by the user. We have to re-create time zone + // since calendar takes ownership. + icu::TimeZone* tz = NULL; + icu::UnicodeString timezone; + if (Utils::ExtractStringSetting(options, "timeZone", &timezone)) { + tz = icu::TimeZone::createTimeZone(timezone); + } else { + tz = icu::TimeZone::createDefault(); + } + + // Create a calendar using locale, and apply time zone to it. + UErrorCode status = U_ZERO_ERROR; + icu::Calendar* calendar = + icu::Calendar::createInstance(tz, icu_locale, status); + + // Make formatter from skeleton. Calendar and numbering system are added + // to the locale as Unicode extension (if they were specified at all). + icu::SimpleDateFormat* date_format = NULL; + icu::UnicodeString skeleton; + if (Utils::ExtractStringSetting(options, "skeleton", &skeleton)) { + icu::DateTimePatternGenerator* generator = + icu::DateTimePatternGenerator::createInstance(icu_locale, status); + icu::UnicodeString pattern; + if (U_SUCCESS(status)) { + pattern = generator->getBestPattern(skeleton, status); + delete generator; + } + + date_format = new icu::SimpleDateFormat(pattern, icu_locale, status); + if (U_SUCCESS(status)) { + date_format->adoptCalendar(calendar); + } + } + + if (U_FAILURE(status)) { + delete calendar; + delete date_format; + date_format = NULL; + } + + return date_format; +} + +static void SetResolvedSettings(const icu::Locale& icu_locale, + icu::SimpleDateFormat* date_format, + v8::Handle<v8::Object> resolved) { + UErrorCode status = U_ZERO_ERROR; + icu::UnicodeString pattern; + date_format->toPattern(pattern); + resolved->Set(v8::String::New("pattern"), + v8::String::New(reinterpret_cast<const uint16_t*>( + pattern.getBuffer()), pattern.length())); + + // Set time zone and calendar. + if (date_format) { + const icu::Calendar* calendar = date_format->getCalendar(); + const char* calendar_name = calendar->getType(); + resolved->Set(v8::String::New("calendar"), v8::String::New(calendar_name)); + + const icu::TimeZone& tz = calendar->getTimeZone(); + icu::UnicodeString time_zone; + tz.getID(time_zone); + + icu::UnicodeString canonical_time_zone; + icu::TimeZone::getCanonicalID(time_zone, canonical_time_zone, status); + if (U_SUCCESS(status)) { + if (canonical_time_zone == UNICODE_STRING_SIMPLE("Etc/GMT")) { + resolved->Set(v8::String::New("timeZone"), v8::String::New("UTC")); + } else { + resolved->Set(v8::String::New("timeZone"), + v8::String::New(reinterpret_cast<const uint16_t*>( + canonical_time_zone.getBuffer()), + canonical_time_zone.length())); + } + } + } + + // Ugly hack. ICU doesn't expose numbering system in any way, so we have + // to assume that for given locale NumberingSystem constructor produces the + // same digits as NumberFormat/Calendar would. + status = U_ZERO_ERROR; + icu::NumberingSystem* numbering_system = + icu::NumberingSystem::createInstance(icu_locale, status); + if (U_SUCCESS(status)) { + const char* ns = numbering_system->getName(); + resolved->Set(v8::String::New("numberingSystem"), v8::String::New(ns)); + } else { + resolved->Set(v8::String::New("numberingSystem"), v8::Undefined()); + } + delete numbering_system; + + // Set the locale + char result[ULOC_FULLNAME_CAPACITY]; + status = U_ZERO_ERROR; + uloc_toLanguageTag( + icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status); + if (U_SUCCESS(status)) { + resolved->Set(v8::String::New("locale"), v8::String::New(result)); + } else { + // This would never happen, since we got the locale from ICU. + resolved->Set(v8::String::New("locale"), v8::String::New("und")); + } +} + +} // namespace v8_i18n diff --git a/chromium/v8/src/extensions/i18n/date-format.h b/chromium/v8/src/extensions/i18n/date-format.h new file mode 100644 index 00000000000..daa5964e254 --- /dev/null +++ b/chromium/v8/src/extensions/i18n/date-format.h @@ -0,0 +1,71 @@ +// Copyright 2013 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. +// limitations under the License. + +#ifndef V8_EXTENSIONS_I18N_DATE_FORMAT_H_ +#define V8_EXTENSIONS_I18N_DATE_FORMAT_H_ + +#include "unicode/uversion.h" +#include "v8.h" + +namespace U_ICU_NAMESPACE { +class SimpleDateFormat; +} + +namespace v8_i18n { + +class DateFormat { + public: + static void JSCreateDateTimeFormat( + const v8::FunctionCallbackInfo<v8::Value>& args); + + // Helper methods for various bindings. + + // Unpacks date format object from corresponding JavaScript object. + static icu::SimpleDateFormat* UnpackDateFormat( + v8::Handle<v8::Object> obj); + + // Release memory we allocated for the DateFormat once the JS object that + // holds the pointer gets garbage collected. + static void DeleteDateFormat(v8::Isolate* isolate, + v8::Persistent<v8::Object>* object, + void* param); + + // Formats date and returns corresponding string. + static void JSInternalFormat(const v8::FunctionCallbackInfo<v8::Value>& args); + + // Parses date and returns corresponding Date object or undefined if parse + // failed. + static void JSInternalParse(const v8::FunctionCallbackInfo<v8::Value>& args); + + private: + DateFormat(); +}; + +} // namespace v8_i18n + +#endif // V8_EXTENSIONS_I18N_DATE_FORMAT_H_ diff --git a/chromium/v8/src/extensions/i18n/date-format.js b/chromium/v8/src/extensions/i18n/date-format.js index b1d28e535cd..04e7a7c7b9d 100644 --- a/chromium/v8/src/extensions/i18n/date-format.js +++ b/chromium/v8/src/extensions/i18n/date-format.js @@ -235,6 +235,7 @@ function toDateTimeOptions(options, required, defaults) { * Useful for subclassing. */ function initializeDateTimeFormat(dateFormat, locales, options) { + native function NativeJSCreateDateTimeFormat(); if (dateFormat.hasOwnProperty('__initializedIntlObject')) { throw new TypeError('Trying to re-initialize DateTimeFormat object.'); @@ -291,7 +292,7 @@ function initializeDateTimeFormat(dateFormat, locales, options) { year: {writable: true} }); - var formatter = %CreateDateTimeFormat( + var formatter = NativeJSCreateDateTimeFormat( requestedLocale, {skeleton: ldmlString, timeZone: tz}, resolved); if (tz !== undefined && tz !== resolved.timeZone) { @@ -408,6 +409,8 @@ function initializeDateTimeFormat(dateFormat, locales, options) { * DateTimeFormat. */ function formatDate(formatter, dateValue) { + native function NativeJSInternalDateFormat(); + var dateMs; if (dateValue === undefined) { dateMs = Date.now(); @@ -419,7 +422,7 @@ function formatDate(formatter, dateValue) { throw new RangeError('Provided date is not in valid range.'); } - return %InternalDateFormat(formatter.formatter, new Date(dateMs)); + return NativeJSInternalDateFormat(formatter.formatter, new Date(dateMs)); } @@ -430,7 +433,8 @@ function formatDate(formatter, dateValue) { * Returns undefined if date string cannot be parsed. */ function parseDate(formatter, value) { - return %InternalDateParse(formatter.formatter, String(value)); + native function NativeJSInternalDateParse(); + return NativeJSInternalDateParse(formatter.formatter, String(value)); } diff --git a/chromium/v8/src/extensions/i18n/i18n-extension.cc b/chromium/v8/src/extensions/i18n/i18n-extension.cc index e2cba8eb9ef..1c77b8899fb 100644 --- a/chromium/v8/src/extensions/i18n/i18n-extension.cc +++ b/chromium/v8/src/extensions/i18n/i18n-extension.cc @@ -29,7 +29,11 @@ #include "i18n-extension.h" #include "break-iterator.h" +#include "collator.h" +#include "date-format.h" +#include "locale.h" #include "natives.h" +#include "number-format.h" using v8::internal::I18NNatives; @@ -45,6 +49,42 @@ Extension::Extension() v8::Handle<v8::FunctionTemplate> Extension::GetNativeFunction( v8::Handle<v8::String> name) { + // Standalone, helper methods. + if (name->Equals(v8::String::New("NativeJSCanonicalizeLanguageTag"))) { + return v8::FunctionTemplate::New(JSCanonicalizeLanguageTag); + } else if (name->Equals(v8::String::New("NativeJSAvailableLocalesOf"))) { + return v8::FunctionTemplate::New(JSAvailableLocalesOf); + } else if (name->Equals(v8::String::New("NativeJSGetDefaultICULocale"))) { + return v8::FunctionTemplate::New(JSGetDefaultICULocale); + } else if (name->Equals(v8::String::New("NativeJSGetLanguageTagVariants"))) { + return v8::FunctionTemplate::New(JSGetLanguageTagVariants); + } + + // Date format and parse. + if (name->Equals(v8::String::New("NativeJSCreateDateTimeFormat"))) { + return v8::FunctionTemplate::New(DateFormat::JSCreateDateTimeFormat); + } else if (name->Equals(v8::String::New("NativeJSInternalDateFormat"))) { + return v8::FunctionTemplate::New(DateFormat::JSInternalFormat); + } else if (name->Equals(v8::String::New("NativeJSInternalDateParse"))) { + return v8::FunctionTemplate::New(DateFormat::JSInternalParse); + } + + // Number format and parse. + if (name->Equals(v8::String::New("NativeJSCreateNumberFormat"))) { + return v8::FunctionTemplate::New(NumberFormat::JSCreateNumberFormat); + } else if (name->Equals(v8::String::New("NativeJSInternalNumberFormat"))) { + return v8::FunctionTemplate::New(NumberFormat::JSInternalFormat); + } else if (name->Equals(v8::String::New("NativeJSInternalNumberParse"))) { + return v8::FunctionTemplate::New(NumberFormat::JSInternalParse); + } + + // Collator. + if (name->Equals(v8::String::New("NativeJSCreateCollator"))) { + return v8::FunctionTemplate::New(Collator::JSCreateCollator); + } else if (name->Equals(v8::String::New("NativeJSInternalCompare"))) { + return v8::FunctionTemplate::New(Collator::JSInternalCompare); + } + // Break iterator. if (name->Equals(v8::String::New("NativeJSCreateBreakIterator"))) { return v8::FunctionTemplate::New(BreakIterator::JSCreateBreakIterator); diff --git a/chromium/v8/src/extensions/i18n/i18n-utils.cc b/chromium/v8/src/extensions/i18n/i18n-utils.cc index 8c87f0715b9..eac11669047 100644 --- a/chromium/v8/src/extensions/i18n/i18n-utils.cc +++ b/chromium/v8/src/extensions/i18n/i18n-utils.cc @@ -141,37 +141,35 @@ void Utils::AsciiToUChar(const char* source, } -static v8::Local<v8::ObjectTemplate> ToLocal(i::Handle<i::Object> handle) { - return v8::Utils::ToLocal(i::Handle<i::ObjectTemplateInfo>::cast(handle)); -} - - -template<int internal_fields, i::EternalHandles::SingletonHandle field> -static v8::Local<v8::ObjectTemplate> GetEternal(v8::Isolate* external) { - i::Isolate* isolate = reinterpret_cast<i::Isolate*>(external); - if (isolate->eternal_handles()->Exists(field)) { - return ToLocal(isolate->eternal_handles()->GetSingleton(field)); - } - v8::Local<v8::ObjectTemplate> raw_template(v8::ObjectTemplate::New()); - raw_template->SetInternalFieldCount(internal_fields); - return ToLocal( - isolate->eternal_handles()->CreateSingleton( - isolate, - *v8::Utils::OpenHandle(*raw_template), - field)); -} - - // static v8::Local<v8::ObjectTemplate> Utils::GetTemplate(v8::Isolate* isolate) { - return GetEternal<1, i::EternalHandles::I18N_TEMPLATE_ONE>(isolate); + i::Isolate* internal = reinterpret_cast<i::Isolate*>(isolate); + if (internal->heap()->i18n_template_one() == + internal->heap()->the_hole_value()) { + v8::Local<v8::ObjectTemplate> raw_template(v8::ObjectTemplate::New()); + raw_template->SetInternalFieldCount(1); + internal->heap() + ->SetI18nTemplateOne(*v8::Utils::OpenHandle(*raw_template)); + } + + return v8::Utils::ToLocal(i::Handle<i::ObjectTemplateInfo>::cast( + internal->factory()->i18n_template_one())); } // static v8::Local<v8::ObjectTemplate> Utils::GetTemplate2(v8::Isolate* isolate) { - return GetEternal<2, i::EternalHandles::I18N_TEMPLATE_TWO>(isolate); -} + i::Isolate* internal = reinterpret_cast<i::Isolate*>(isolate); + if (internal->heap()->i18n_template_two() == + internal->heap()->the_hole_value()) { + v8::Local<v8::ObjectTemplate> raw_template(v8::ObjectTemplate::New()); + raw_template->SetInternalFieldCount(2); + internal->heap() + ->SetI18nTemplateTwo(*v8::Utils::OpenHandle(*raw_template)); + } + return v8::Utils::ToLocal(i::Handle<i::ObjectTemplateInfo>::cast( + internal->factory()->i18n_template_two())); +} } // namespace v8_i18n diff --git a/chromium/v8/src/extensions/i18n/i18n-utils.js b/chromium/v8/src/extensions/i18n/i18n-utils.js index 545082ecbba..d7e9486c507 100644 --- a/chromium/v8/src/extensions/i18n/i18n-utils.js +++ b/chromium/v8/src/extensions/i18n/i18n-utils.js @@ -255,6 +255,8 @@ function resolveLocale(service, requestedLocales, options) { * lookup algorithm. */ function lookupMatcher(service, requestedLocales) { + native function NativeJSGetDefaultICULocale(); + if (service.match(SERVICE_RE) === null) { throw new Error('Internal error, wrong service type: ' + service); } @@ -285,7 +287,7 @@ function lookupMatcher(service, requestedLocales) { // Didn't find a match, return default. if (DEFAULT_ICU_LOCALE === undefined) { - DEFAULT_ICU_LOCALE = %GetDefaultICULocale(); + DEFAULT_ICU_LOCALE = NativeJSGetDefaultICULocale(); } return {'locale': DEFAULT_ICU_LOCALE, 'extension': '', 'position': -1}; @@ -444,12 +446,14 @@ function getOptimalLanguageTag(original, resolved) { // Returns Array<Object>, where each object has maximized and base properties. // Maximized: zh -> zh-Hans-CN // Base: zh-CN-u-ca-gregory -> zh-CN + native function NativeJSGetLanguageTagVariants(); + // Take care of grandfathered or simple cases. if (original === resolved) { return original; } - var locales = %GetLanguageTagVariants([original, resolved]); + var locales = NativeJSGetLanguageTagVariants([original, resolved]); if (locales[0].maximized !== locales[1].maximized) { return resolved; } @@ -467,7 +471,8 @@ function getOptimalLanguageTag(original, resolved) { * that is supported. This is required by the spec. */ function getAvailableLocalesOf(service) { - var available = %AvailableLocalesOf(service); + native function NativeJSAvailableLocalesOf(); + var available = NativeJSAvailableLocalesOf(service); for (var i in available) { if (available.hasOwnProperty(i)) { diff --git a/chromium/v8/src/extensions/i18n/locale.cc b/chromium/v8/src/extensions/i18n/locale.cc new file mode 100644 index 00000000000..6b6f9ac314d --- /dev/null +++ b/chromium/v8/src/extensions/i18n/locale.cc @@ -0,0 +1,251 @@ +// Copyright 2013 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. +// limitations under the License. + +#include "locale.h" + +#include <string.h> + +#include "unicode/brkiter.h" +#include "unicode/coll.h" +#include "unicode/datefmt.h" +#include "unicode/numfmt.h" +#include "unicode/uloc.h" +#include "unicode/uversion.h" + +namespace v8_i18n { + +void JSCanonicalizeLanguageTag( + const v8::FunctionCallbackInfo<v8::Value>& args) { + // Expect locale id which is a string. + if (args.Length() != 1 || !args[0]->IsString()) { + v8::ThrowException(v8::Exception::SyntaxError( + v8::String::New("Locale identifier, as a string, is required."))); + return; + } + + UErrorCode error = U_ZERO_ERROR; + + char icu_result[ULOC_FULLNAME_CAPACITY]; + int icu_length = 0; + + // Return value which denotes invalid language tag. + const char* const kInvalidTag = "invalid-tag"; + + v8::String::AsciiValue locale_id(args[0]->ToString()); + if (*locale_id == NULL) { + args.GetReturnValue().Set(v8::String::New(kInvalidTag)); + return; + } + + uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY, + &icu_length, &error); + if (U_FAILURE(error) || icu_length == 0) { + args.GetReturnValue().Set(v8::String::New(kInvalidTag)); + return; + } + + char result[ULOC_FULLNAME_CAPACITY]; + + // Force strict BCP47 rules. + uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error); + + if (U_FAILURE(error)) { + args.GetReturnValue().Set(v8::String::New(kInvalidTag)); + return; + } + + args.GetReturnValue().Set(v8::String::New(result)); +} + + +void JSAvailableLocalesOf(const v8::FunctionCallbackInfo<v8::Value>& args) { + // Expect service name which is a string. + if (args.Length() != 1 || !args[0]->IsString()) { + v8::ThrowException(v8::Exception::SyntaxError( + v8::String::New("Service identifier, as a string, is required."))); + return; + } + + const icu::Locale* available_locales = NULL; + + int32_t count = 0; + v8::String::AsciiValue service(args[0]->ToString()); + if (strcmp(*service, "collator") == 0) { + available_locales = icu::Collator::getAvailableLocales(count); + } else if (strcmp(*service, "numberformat") == 0) { + available_locales = icu::NumberFormat::getAvailableLocales(count); + } else if (strcmp(*service, "dateformat") == 0) { + available_locales = icu::DateFormat::getAvailableLocales(count); + } else if (strcmp(*service, "breakiterator") == 0) { + available_locales = icu::BreakIterator::getAvailableLocales(count); + } + + v8::TryCatch try_catch; + UErrorCode error = U_ZERO_ERROR; + char result[ULOC_FULLNAME_CAPACITY]; + v8::Handle<v8::Object> locales = v8::Object::New(); + + for (int32_t i = 0; i < count; ++i) { + const char* icu_name = available_locales[i].getName(); + + error = U_ZERO_ERROR; + // No need to force strict BCP47 rules. + uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error); + if (U_FAILURE(error)) { + // This shouldn't happen, but lets not break the user. + continue; + } + + // Index is just a dummy value for the property value. + locales->Set(v8::String::New(result), v8::Integer::New(i)); + if (try_catch.HasCaught()) { + // Ignore error, but stop processing and return. + break; + } + } + + args.GetReturnValue().Set(locales); +} + + +void JSGetDefaultICULocale(const v8::FunctionCallbackInfo<v8::Value>& args) { + icu::Locale default_locale; + + // Set the locale + char result[ULOC_FULLNAME_CAPACITY]; + UErrorCode status = U_ZERO_ERROR; + uloc_toLanguageTag( + default_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status); + if (U_SUCCESS(status)) { + args.GetReturnValue().Set(v8::String::New(result)); + return; + } + + args.GetReturnValue().Set(v8::String::New("und")); +} + + +void JSGetLanguageTagVariants(const v8::FunctionCallbackInfo<v8::Value>& args) { + v8::TryCatch try_catch; + + // Expect an array of strings. + if (args.Length() != 1 || !args[0]->IsArray()) { + v8::ThrowException(v8::Exception::SyntaxError( + v8::String::New("Internal error. Expected Array<String>."))); + return; + } + + v8::Local<v8::Array> input = v8::Local<v8::Array>::Cast(args[0]); + v8::Handle<v8::Array> output = v8::Array::New(input->Length()); + for (unsigned int i = 0; i < input->Length(); ++i) { + v8::Local<v8::Value> locale_id = input->Get(i); + if (try_catch.HasCaught()) { + break; + } + + if (!locale_id->IsString()) { + v8::ThrowException(v8::Exception::SyntaxError( + v8::String::New("Internal error. Array element is missing " + "or it isn't a string."))); + return; + } + + v8::String::AsciiValue ascii_locale_id(locale_id); + if (*ascii_locale_id == NULL) { + v8::ThrowException(v8::Exception::SyntaxError( + v8::String::New("Internal error. Non-ASCII locale identifier."))); + return; + } + + UErrorCode error = U_ZERO_ERROR; + + // Convert from BCP47 to ICU format. + // de-DE-u-co-phonebk -> de_DE@collation=phonebook + char icu_locale[ULOC_FULLNAME_CAPACITY]; + int icu_locale_length = 0; + uloc_forLanguageTag(*ascii_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY, + &icu_locale_length, &error); + if (U_FAILURE(error) || icu_locale_length == 0) { + v8::ThrowException(v8::Exception::SyntaxError( + v8::String::New("Internal error. Failed to convert locale to ICU."))); + return; + } + + // Maximize the locale. + // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook + char icu_max_locale[ULOC_FULLNAME_CAPACITY]; + uloc_addLikelySubtags( + icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY, &error); + + // Remove extensions from maximized locale. + // de_Latn_DE@collation=phonebook -> de_Latn_DE + char icu_base_max_locale[ULOC_FULLNAME_CAPACITY]; + uloc_getBaseName( + icu_max_locale, icu_base_max_locale, ULOC_FULLNAME_CAPACITY, &error); + + // Get original name without extensions. + // de_DE@collation=phonebook -> de_DE + char icu_base_locale[ULOC_FULLNAME_CAPACITY]; + uloc_getBaseName( + icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY, &error); + + // Convert from ICU locale format to BCP47 format. + // de_Latn_DE -> de-Latn-DE + char base_max_locale[ULOC_FULLNAME_CAPACITY]; + uloc_toLanguageTag(icu_base_max_locale, base_max_locale, + ULOC_FULLNAME_CAPACITY, FALSE, &error); + + // de_DE -> de-DE + char base_locale[ULOC_FULLNAME_CAPACITY]; + uloc_toLanguageTag( + icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY, FALSE, &error); + + if (U_FAILURE(error)) { + v8::ThrowException(v8::Exception::SyntaxError( + v8::String::New("Internal error. Couldn't generate maximized " + "or base locale."))); + return; + } + + v8::Handle<v8::Object> result = v8::Object::New(); + result->Set(v8::String::New("maximized"), v8::String::New(base_max_locale)); + result->Set(v8::String::New("base"), v8::String::New(base_locale)); + if (try_catch.HasCaught()) { + break; + } + + output->Set(i, result); + if (try_catch.HasCaught()) { + break; + } + } + + args.GetReturnValue().Set(output); +} + +} // namespace v8_i18n diff --git a/chromium/v8/src/extensions/i18n/locale.h b/chromium/v8/src/extensions/i18n/locale.h new file mode 100644 index 00000000000..c39568e5d9d --- /dev/null +++ b/chromium/v8/src/extensions/i18n/locale.h @@ -0,0 +1,56 @@ +// Copyright 2013 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. +// limitations under the License. + +#ifndef V8_EXTENSIONS_I18N_SRC_LOCALE_H_ +#define V8_EXTENSIONS_I18N_SRC_LOCALE_H_ + +#include "unicode/uversion.h" +#include "v8.h" + +namespace v8_i18n { + +// Canonicalizes the BCP47 language tag using BCP47 rules. +// Returns 'invalid-tag' in case input was not well formed. +void JSCanonicalizeLanguageTag(const v8::FunctionCallbackInfo<v8::Value>& args); + +// Returns a list of available locales for collator, date or number formatter. +void JSAvailableLocalesOf(const v8::FunctionCallbackInfo<v8::Value>& args); + +// Returns default ICU locale. +void JSGetDefaultICULocale(const v8::FunctionCallbackInfo<v8::Value>& args); + +// Returns an array of objects, that have maximized and base names of inputs. +// Unicode extensions are dropped from both. +// Input: ['zh-TW-u-nu-thai', 'sr'] +// Output: [{maximized: 'zh-Hant-TW', base: 'zh-TW'}, +// {maximized: 'sr-Cyrl-RS', base: 'sr'}] +void JSGetLanguageTagVariants(const v8::FunctionCallbackInfo<v8::Value>& args); + +} // namespace v8_i18n + +#endif // V8_EXTENSIONS_I18N_LOCALE_H_ diff --git a/chromium/v8/src/extensions/i18n/locale.js b/chromium/v8/src/extensions/i18n/locale.js index e4783277e64..ea95b87192e 100644 --- a/chromium/v8/src/extensions/i18n/locale.js +++ b/chromium/v8/src/extensions/i18n/locale.js @@ -34,6 +34,8 @@ * Canonicalizes the language tag, or throws in case the tag is invalid. */ function canonicalizeLanguageTag(localeID) { + native function NativeJSCanonicalizeLanguageTag(); + // null is typeof 'object' so we have to do extra check. if (typeof localeID !== 'string' && typeof localeID !== 'object' || localeID === null) { @@ -50,7 +52,7 @@ function canonicalizeLanguageTag(localeID) { // ICU bug filled - http://bugs.icu-project.org/trac/ticket/9265. // TODO(cira): check if -u-kn-true-kc-true-kh-true still throws after // upgrade to ICU 4.9. - var tag = %CanonicalizeLanguageTag(localeString); + var tag = NativeJSCanonicalizeLanguageTag(localeString); if (tag === 'invalid-tag') { throw new RangeError('Invalid language tag: ' + localeString); } diff --git a/chromium/v8/src/extensions/i18n/number-format.cc b/chromium/v8/src/extensions/i18n/number-format.cc new file mode 100644 index 00000000000..136471561c4 --- /dev/null +++ b/chromium/v8/src/extensions/i18n/number-format.cc @@ -0,0 +1,418 @@ +// Copyright 2013 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. +// limitations under the License. + +#include "number-format.h" + +#include <string.h> + +#include "i18n-utils.h" +#include "unicode/curramt.h" +#include "unicode/dcfmtsym.h" +#include "unicode/decimfmt.h" +#include "unicode/locid.h" +#include "unicode/numfmt.h" +#include "unicode/numsys.h" +#include "unicode/uchar.h" +#include "unicode/ucurr.h" +#include "unicode/unum.h" +#include "unicode/uversion.h" + +namespace v8_i18n { + +static icu::DecimalFormat* InitializeNumberFormat(v8::Handle<v8::String>, + v8::Handle<v8::Object>, + v8::Handle<v8::Object>); +static icu::DecimalFormat* CreateICUNumberFormat(const icu::Locale&, + v8::Handle<v8::Object>); +static void SetResolvedSettings(const icu::Locale&, + icu::DecimalFormat*, + v8::Handle<v8::Object>); + +icu::DecimalFormat* NumberFormat::UnpackNumberFormat( + v8::Handle<v8::Object> obj) { + v8::HandleScope handle_scope; + + // v8::ObjectTemplate doesn't have HasInstance method so we can't check + // if obj is an instance of NumberFormat class. We'll check for a property + // that has to be in the object. The same applies to other services, like + // Collator and DateTimeFormat. + if (obj->HasOwnProperty(v8::String::New("numberFormat"))) { + return static_cast<icu::DecimalFormat*>( + obj->GetAlignedPointerFromInternalField(0)); + } + + return NULL; +} + +void NumberFormat::DeleteNumberFormat(v8::Isolate* isolate, + v8::Persistent<v8::Object>* object, + void* param) { + // First delete the hidden C++ object. + // Unpacking should never return NULL here. That would only happen if + // this method is used as the weak callback for persistent handles not + // pointing to a date time formatter. + v8::HandleScope handle_scope(isolate); + v8::Local<v8::Object> handle = v8::Local<v8::Object>::New(isolate, *object); + delete UnpackNumberFormat(handle); + + // Then dispose of the persistent handle to JS object. + object->Dispose(isolate); +} + +void NumberFormat::JSInternalFormat( + const v8::FunctionCallbackInfo<v8::Value>& args) { + if (args.Length() != 2 || !args[0]->IsObject() || !args[1]->IsNumber()) { + v8::ThrowException(v8::Exception::Error( + v8::String::New("Formatter and numeric value have to be specified."))); + return; + } + + icu::DecimalFormat* number_format = UnpackNumberFormat(args[0]->ToObject()); + if (!number_format) { + v8::ThrowException(v8::Exception::Error( + v8::String::New("NumberFormat method called on an object " + "that is not a NumberFormat."))); + return; + } + + // ICU will handle actual NaN value properly and return NaN string. + icu::UnicodeString result; + number_format->format(args[1]->NumberValue(), result); + + args.GetReturnValue().Set(v8::String::New( + reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length())); +} + +void NumberFormat::JSInternalParse( + const v8::FunctionCallbackInfo<v8::Value>& args) { + if (args.Length() != 2 || !args[0]->IsObject() || !args[1]->IsString()) { + v8::ThrowException(v8::Exception::Error( + v8::String::New("Formatter and string have to be specified."))); + return; + } + + icu::DecimalFormat* number_format = UnpackNumberFormat(args[0]->ToObject()); + if (!number_format) { + v8::ThrowException(v8::Exception::Error( + v8::String::New("NumberFormat method called on an object " + "that is not a NumberFormat."))); + return; + } + + // ICU will handle actual NaN value properly and return NaN string. + icu::UnicodeString string_number; + if (!Utils::V8StringToUnicodeString(args[1]->ToString(), &string_number)) { + string_number = ""; + } + + UErrorCode status = U_ZERO_ERROR; + icu::Formattable result; + // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49 + // to be part of Chrome. + // TODO(cira): Include currency parsing code using parseCurrency call. + // We need to check if the formatter parses all currencies or only the + // one it was constructed with (it will impact the API - how to return ISO + // code and the value). + number_format->parse(string_number, result, status); + if (U_FAILURE(status)) { + return; + } + + switch (result.getType()) { + case icu::Formattable::kDouble: + args.GetReturnValue().Set(result.getDouble()); + return; + case icu::Formattable::kLong: + args.GetReturnValue().Set(result.getLong()); + return; + case icu::Formattable::kInt64: + args.GetReturnValue().Set(static_cast<double>(result.getInt64())); + return; + default: + return; + } +} + +void NumberFormat::JSCreateNumberFormat( + const v8::FunctionCallbackInfo<v8::Value>& args) { + if (args.Length() != 3 || + !args[0]->IsString() || + !args[1]->IsObject() || + !args[2]->IsObject()) { + v8::ThrowException(v8::Exception::Error( + v8::String::New("Internal error, wrong parameters."))); + return; + } + + v8::Isolate* isolate = args.GetIsolate(); + v8::Local<v8::ObjectTemplate> number_format_template = + Utils::GetTemplate(isolate); + + // Create an empty object wrapper. + v8::Local<v8::Object> local_object = number_format_template->NewInstance(); + // But the handle shouldn't be empty. + // That can happen if there was a stack overflow when creating the object. + if (local_object.IsEmpty()) { + args.GetReturnValue().Set(local_object); + return; + } + + // Set number formatter as internal field of the resulting JS object. + icu::DecimalFormat* number_format = InitializeNumberFormat( + args[0]->ToString(), args[1]->ToObject(), args[2]->ToObject()); + + if (!number_format) { + v8::ThrowException(v8::Exception::Error(v8::String::New( + "Internal error. Couldn't create ICU number formatter."))); + return; + } else { + local_object->SetAlignedPointerInInternalField(0, number_format); + + v8::TryCatch try_catch; + local_object->Set(v8::String::New("numberFormat"), + v8::String::New("valid")); + if (try_catch.HasCaught()) { + v8::ThrowException(v8::Exception::Error( + v8::String::New("Internal error, couldn't set property."))); + return; + } + } + + v8::Persistent<v8::Object> wrapper(isolate, local_object); + // Make object handle weak so we can delete iterator once GC kicks in. + wrapper.MakeWeak<void>(NULL, &DeleteNumberFormat); + args.GetReturnValue().Set(wrapper); + wrapper.ClearAndLeak(); +} + +static icu::DecimalFormat* InitializeNumberFormat( + v8::Handle<v8::String> locale, + v8::Handle<v8::Object> options, + v8::Handle<v8::Object> resolved) { + // Convert BCP47 into ICU locale format. + UErrorCode status = U_ZERO_ERROR; + icu::Locale icu_locale; + char icu_result[ULOC_FULLNAME_CAPACITY]; + int icu_length = 0; + v8::String::AsciiValue bcp47_locale(locale); + if (bcp47_locale.length() != 0) { + uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY, + &icu_length, &status); + if (U_FAILURE(status) || icu_length == 0) { + return NULL; + } + icu_locale = icu::Locale(icu_result); + } + + icu::DecimalFormat* number_format = + CreateICUNumberFormat(icu_locale, options); + if (!number_format) { + // Remove extensions and try again. + icu::Locale no_extension_locale(icu_locale.getBaseName()); + number_format = CreateICUNumberFormat(no_extension_locale, options); + + // Set resolved settings (pattern, numbering system). + SetResolvedSettings(no_extension_locale, number_format, resolved); + } else { + SetResolvedSettings(icu_locale, number_format, resolved); + } + + return number_format; +} + +static icu::DecimalFormat* CreateICUNumberFormat( + const icu::Locale& icu_locale, v8::Handle<v8::Object> options) { + // Make formatter from options. Numbering system is added + // to the locale as Unicode extension (if it was specified at all). + UErrorCode status = U_ZERO_ERROR; + icu::DecimalFormat* number_format = NULL; + icu::UnicodeString style; + icu::UnicodeString currency; + if (Utils::ExtractStringSetting(options, "style", &style)) { + if (style == UNICODE_STRING_SIMPLE("currency")) { + Utils::ExtractStringSetting(options, "currency", ¤cy); + + icu::UnicodeString display; + Utils::ExtractStringSetting(options, "currencyDisplay", &display); +#if (U_ICU_VERSION_MAJOR_NUM == 4) && (U_ICU_VERSION_MINOR_NUM <= 6) + icu::NumberFormat::EStyles style; + if (display == UNICODE_STRING_SIMPLE("code")) { + style = icu::NumberFormat::kIsoCurrencyStyle; + } else if (display == UNICODE_STRING_SIMPLE("name")) { + style = icu::NumberFormat::kPluralCurrencyStyle; + } else { + style = icu::NumberFormat::kCurrencyStyle; + } +#else // ICU version is 4.8 or above (we ignore versions below 4.0). + UNumberFormatStyle style; + if (display == UNICODE_STRING_SIMPLE("code")) { + style = UNUM_CURRENCY_ISO; + } else if (display == UNICODE_STRING_SIMPLE("name")) { + style = UNUM_CURRENCY_PLURAL; + } else { + style = UNUM_CURRENCY; + } +#endif + + number_format = static_cast<icu::DecimalFormat*>( + icu::NumberFormat::createInstance(icu_locale, style, status)); + } else if (style == UNICODE_STRING_SIMPLE("percent")) { + number_format = static_cast<icu::DecimalFormat*>( + icu::NumberFormat::createPercentInstance(icu_locale, status)); + if (U_FAILURE(status)) { + delete number_format; + return NULL; + } + // Make sure 1.1% doesn't go into 2%. + number_format->setMinimumFractionDigits(1); + } else { + // Make a decimal instance by default. + number_format = static_cast<icu::DecimalFormat*>( + icu::NumberFormat::createInstance(icu_locale, status)); + } + } + + if (U_FAILURE(status)) { + delete number_format; + return NULL; + } + + // Set all options. + if (!currency.isEmpty()) { + number_format->setCurrency(currency.getBuffer(), status); + } + + int32_t digits; + if (Utils::ExtractIntegerSetting( + options, "minimumIntegerDigits", &digits)) { + number_format->setMinimumIntegerDigits(digits); + } + + if (Utils::ExtractIntegerSetting( + options, "minimumFractionDigits", &digits)) { + number_format->setMinimumFractionDigits(digits); + } + + if (Utils::ExtractIntegerSetting( + options, "maximumFractionDigits", &digits)) { + number_format->setMaximumFractionDigits(digits); + } + + bool significant_digits_used = false; + if (Utils::ExtractIntegerSetting( + options, "minimumSignificantDigits", &digits)) { + number_format->setMinimumSignificantDigits(digits); + significant_digits_used = true; + } + + if (Utils::ExtractIntegerSetting( + options, "maximumSignificantDigits", &digits)) { + number_format->setMaximumSignificantDigits(digits); + significant_digits_used = true; + } + + number_format->setSignificantDigitsUsed(significant_digits_used); + + bool grouping; + if (Utils::ExtractBooleanSetting(options, "useGrouping", &grouping)) { + number_format->setGroupingUsed(grouping); + } + + // Set rounding mode. + number_format->setRoundingMode(icu::DecimalFormat::kRoundHalfUp); + + return number_format; +} + +static void SetResolvedSettings(const icu::Locale& icu_locale, + icu::DecimalFormat* number_format, + v8::Handle<v8::Object> resolved) { + icu::UnicodeString pattern; + number_format->toPattern(pattern); + resolved->Set(v8::String::New("pattern"), + v8::String::New(reinterpret_cast<const uint16_t*>( + pattern.getBuffer()), pattern.length())); + + // Set resolved currency code in options.currency if not empty. + icu::UnicodeString currency(number_format->getCurrency()); + if (!currency.isEmpty()) { + resolved->Set(v8::String::New("currency"), + v8::String::New(reinterpret_cast<const uint16_t*>( + currency.getBuffer()), currency.length())); + } + + // Ugly hack. ICU doesn't expose numbering system in any way, so we have + // to assume that for given locale NumberingSystem constructor produces the + // same digits as NumberFormat would. + UErrorCode status = U_ZERO_ERROR; + icu::NumberingSystem* numbering_system = + icu::NumberingSystem::createInstance(icu_locale, status); + if (U_SUCCESS(status)) { + const char* ns = numbering_system->getName(); + resolved->Set(v8::String::New("numberingSystem"), v8::String::New(ns)); + } else { + resolved->Set(v8::String::New("numberingSystem"), v8::Undefined()); + } + delete numbering_system; + + resolved->Set(v8::String::New("useGrouping"), + v8::Boolean::New(number_format->isGroupingUsed())); + + resolved->Set(v8::String::New("minimumIntegerDigits"), + v8::Integer::New(number_format->getMinimumIntegerDigits())); + + resolved->Set(v8::String::New("minimumFractionDigits"), + v8::Integer::New(number_format->getMinimumFractionDigits())); + + resolved->Set(v8::String::New("maximumFractionDigits"), + v8::Integer::New(number_format->getMaximumFractionDigits())); + + if (resolved->HasOwnProperty(v8::String::New("minimumSignificantDigits"))) { + resolved->Set(v8::String::New("minimumSignificantDigits"), v8::Integer::New( + number_format->getMinimumSignificantDigits())); + } + + if (resolved->HasOwnProperty(v8::String::New("maximumSignificantDigits"))) { + resolved->Set(v8::String::New("maximumSignificantDigits"), v8::Integer::New( + number_format->getMaximumSignificantDigits())); + } + + // Set the locale + char result[ULOC_FULLNAME_CAPACITY]; + status = U_ZERO_ERROR; + uloc_toLanguageTag( + icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status); + if (U_SUCCESS(status)) { + resolved->Set(v8::String::New("locale"), v8::String::New(result)); + } else { + // This would never happen, since we got the locale from ICU. + resolved->Set(v8::String::New("locale"), v8::String::New("und")); + } +} + +} // namespace v8_i18n diff --git a/chromium/v8/src/extensions/i18n/number-format.h b/chromium/v8/src/extensions/i18n/number-format.h new file mode 100644 index 00000000000..d4dbc4d6f3b --- /dev/null +++ b/chromium/v8/src/extensions/i18n/number-format.h @@ -0,0 +1,69 @@ +// Copyright 2013 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. +// limitations under the License. + +#ifndef V8_EXTENSIONS_I18N_NUMBER_FORMAT_H_ +#define V8_EXTENSIONS_I18N_NUMBER_FORMAT_H_ + +#include "unicode/uversion.h" +#include "v8.h" + +namespace U_ICU_NAMESPACE { +class DecimalFormat; +} + +namespace v8_i18n { + +class NumberFormat { + public: + static void JSCreateNumberFormat( + const v8::FunctionCallbackInfo<v8::Value>& args); + + // Helper methods for various bindings. + + // Unpacks date format object from corresponding JavaScript object. + static icu::DecimalFormat* UnpackNumberFormat(v8::Handle<v8::Object> obj); + + // Release memory we allocated for the NumberFormat once the JS object that + // holds the pointer gets garbage collected. + static void DeleteNumberFormat(v8::Isolate* isolate, + v8::Persistent<v8::Object>* object, + void* param); + + // Formats number and returns corresponding string. + static void JSInternalFormat(const v8::FunctionCallbackInfo<v8::Value>& args); + + // Parses a string and returns a number. + static void JSInternalParse(const v8::FunctionCallbackInfo<v8::Value>& args); + + private: + NumberFormat(); +}; + +} // namespace v8_i18n + +#endif // V8_EXTENSIONS_I18N_NUMBER_FORMAT_H_ diff --git a/chromium/v8/src/extensions/i18n/number-format.js b/chromium/v8/src/extensions/i18n/number-format.js index 5722a5dc1f3..1cd3db13554 100644 --- a/chromium/v8/src/extensions/i18n/number-format.js +++ b/chromium/v8/src/extensions/i18n/number-format.js @@ -65,6 +65,8 @@ function getNumberOption(options, property, min, max, fallback) { * Useful for subclassing. */ function initializeNumberFormat(numberFormat, locales, options) { + native function NativeJSCreateNumberFormat(); + if (numberFormat.hasOwnProperty('__initializedIntlObject')) { throw new TypeError('Trying to re-initialize NumberFormat object.'); } @@ -146,9 +148,9 @@ function initializeNumberFormat(numberFormat, locales, options) { if (internalOptions.hasOwnProperty('maximumSignificantDigits')) { defineWEProperty(resolved, 'maximumSignificantDigits', undefined); } - var formatter = %CreateNumberFormat(requestedLocale, - internalOptions, - resolved); + var formatter = NativeJSCreateNumberFormat(requestedLocale, + internalOptions, + resolved); // We can't get information about number or currency style from ICU, so we // assume user request was fulfilled. @@ -267,13 +269,15 @@ function initializeNumberFormat(numberFormat, locales, options) { * NumberFormat. */ function formatNumber(formatter, value) { + native function NativeJSInternalNumberFormat(); + // Spec treats -0 and +0 as 0. var number = Number(value); if (number === -0) { number = 0; } - return %InternalNumberFormat(formatter.formatter, number); + return NativeJSInternalNumberFormat(formatter.formatter, number); } @@ -281,7 +285,9 @@ function formatNumber(formatter, value) { * Returns a Number that represents string value that was passed in. */ function parseNumber(formatter, value) { - return %InternalNumberParse(formatter.formatter, String(value)); + native function NativeJSInternalNumberParse(); + + return NativeJSInternalNumberParse(formatter.formatter, String(value)); } diff --git a/chromium/v8/src/factory.cc b/chromium/v8/src/factory.cc index 9323c2f1f03..3ca0efa2107 100644 --- a/chromium/v8/src/factory.cc +++ b/chromium/v8/src/factory.cc @@ -1023,11 +1023,10 @@ Handle<GlobalObject> Factory::NewGlobalObject( Handle<JSObject> Factory::NewJSObjectFromMap(Handle<Map> map, - PretenureFlag pretenure, - bool alloc_props) { + PretenureFlag pretenure) { CALL_HEAP_FUNCTION( isolate(), - isolate()->heap()->AllocateJSObjectFromMap(*map, pretenure, alloc_props), + isolate()->heap()->AllocateJSObjectFromMap(*map, pretenure), JSObject); } @@ -1216,7 +1215,6 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo( shared->set_num_literals(literals_array_size); if (is_generator) { shared->set_instance_class_name(isolate()->heap()->Generator_string()); - shared->DisableOptimization(kGenerator); } return shared; } @@ -1393,10 +1391,8 @@ Handle<JSFunction> Factory::CreateApiFunction( Smi::cast(instance_template->internal_field_count())->value(); } - // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing - // JSObject::GetHeaderSize. int instance_size = kPointerSize * internal_field_count; - InstanceType type; + InstanceType type = INVALID_TYPE; switch (instance_type) { case JavaScriptObject: type = JS_OBJECT_TYPE; @@ -1411,10 +1407,9 @@ Handle<JSFunction> Factory::CreateApiFunction( instance_size += JSGlobalProxy::kSize; break; default: - UNREACHABLE(); - type = JS_OBJECT_TYPE; // Keep the compiler happy. break; } + ASSERT(type != INVALID_TYPE); Handle<JSFunction> result = NewFunction(Factory::empty_string(), diff --git a/chromium/v8/src/factory.h b/chromium/v8/src/factory.h index 02c9a4d2eb4..dc7933aa20f 100644 --- a/chromium/v8/src/factory.h +++ b/chromium/v8/src/factory.h @@ -301,11 +301,7 @@ class Factory { // JS objects are pretenured when allocated by the bootstrapper and // runtime. Handle<JSObject> NewJSObjectFromMap(Handle<Map> map, - PretenureFlag pretenure = NOT_TENURED, - bool allocate_properties = true); - - Handle<JSObject> NewJSObjectFromMapForDeoptimizer( - Handle<Map> map, PretenureFlag pretenure = NOT_TENURED); + PretenureFlag pretenure = NOT_TENURED); // JS modules are pretenured. Handle<JSModule> NewJSModule(Handle<Context> context, diff --git a/chromium/v8/src/flag-definitions.h b/chromium/v8/src/flag-definitions.h index c0ad4a8e17a..5fc5d880b3e 100644 --- a/chromium/v8/src/flag-definitions.h +++ b/chromium/v8/src/flag-definitions.h @@ -174,7 +174,6 @@ DEFINE_bool(harmony_iteration, false, "enable harmony iteration (for-of)") DEFINE_bool(harmony_numeric_literals, false, "enable harmony numeric literals (0o77, 0b11)") DEFINE_bool(harmony_strings, false, "enable harmony string") -DEFINE_bool(harmony_arrays, false, "enable harmony arrays") DEFINE_bool(harmony, false, "enable all harmony features (except typeof)") DEFINE_implication(harmony, harmony_scoping) DEFINE_implication(harmony, harmony_modules) @@ -186,7 +185,6 @@ DEFINE_implication(harmony, harmony_generators) DEFINE_implication(harmony, harmony_iteration) DEFINE_implication(harmony, harmony_numeric_literals) DEFINE_implication(harmony, harmony_strings) -DEFINE_implication(harmony, harmony_arrays) DEFINE_implication(harmony_modules, harmony_scoping) DEFINE_implication(harmony_observation, harmony_collections) // TODO[dslomov] add harmony => harmony_typed_arrays @@ -264,11 +262,10 @@ DEFINE_int(deopt_every_n_garbage_collections, "deoptimize every n garbage collections") DEFINE_bool(print_deopt_stress, false, "print number of possible deopt points") DEFINE_bool(trap_on_deopt, false, "put a break point before deoptimizing") -DEFINE_bool(trap_on_stub_deopt, false, - "put a break point before deoptimizing a stub") DEFINE_bool(deoptimize_uncommon_cases, true, "deoptimize uncommon cases") DEFINE_bool(polymorphic_inlining, true, "polymorphic inlining") DEFINE_bool(use_osr, true, "use on-stack replacement") +DEFINE_bool(idefs, false, "use informative definitions") DEFINE_bool(array_bounds_checks_elimination, true, "perform array bounds checks elimination") DEFINE_bool(array_bounds_checks_hoisting, false, @@ -312,6 +309,9 @@ DEFINE_int(parallel_recompilation_queue_length, 8, "the length of the parallel compilation queue") DEFINE_int(parallel_recompilation_delay, 0, "artificial compilation delay in ms") +DEFINE_bool(omit_prototype_checks_for_leaf_maps, true, + "do not emit prototype checks if all prototypes have leaf maps, " + "deoptimize the optimized code if the layout of the maps changes.") DEFINE_bool(omit_map_checks_for_leaf_maps, true, "do not emit check maps for constant values that have a leaf map, " "deoptimize the optimized code if the layout of the maps changes.") diff --git a/chromium/v8/src/full-codegen.cc b/chromium/v8/src/full-codegen.cc index f5539e8b187..6d802e965d2 100644 --- a/chromium/v8/src/full-codegen.cc +++ b/chromium/v8/src/full-codegen.cc @@ -512,7 +512,7 @@ void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const { void FullCodeGenerator::StackValueContext::Plug(Register reg) const { - __ Push(reg); + __ push(reg); } @@ -530,7 +530,7 @@ void FullCodeGenerator::EffectContext::PlugTOS() const { void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const { - __ Pop(result_register()); + __ pop(result_register()); } @@ -540,7 +540,7 @@ void FullCodeGenerator::StackValueContext::PlugTOS() const { void FullCodeGenerator::TestContext::PlugTOS() const { // For simplicity we always test the accumulator register. - __ Pop(result_register()); + __ pop(result_register()); codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL); codegen()->DoTest(this); } @@ -1006,7 +1006,7 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) { VisitForAccumulatorValue(left); // We want the value in the accumulator for the test, and on the stack in // case we need it. - __ Push(result_register()); + __ push(result_register()); Label discard, restore; if (is_logical_and) { DoTest(left, &discard, &restore, &restore); @@ -1014,7 +1014,7 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) { DoTest(left, &restore, &discard, &restore); } __ bind(&restore); - __ Pop(result_register()); + __ pop(result_register()); __ jmp(&done); __ bind(&discard); __ Drop(1); @@ -1024,7 +1024,7 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) { VisitForAccumulatorValue(left); // We want the value in the accumulator for the test, and on the stack in // case we need it. - __ Push(result_register()); + __ push(result_register()); Label discard; if (is_logical_and) { DoTest(left, &discard, &done, &discard); @@ -1416,7 +1416,7 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { // Extend the context before executing the catch block. { Comment cmnt(masm_, "[ Extend catch context"); __ Push(stmt->variable()->name()); - __ Push(result_register()); + __ push(result_register()); PushFunctionArgumentForContextAllocation(); __ CallRuntime(Runtime::kPushCatchContext, 3); StoreToFrameField(StandardFrameConstants::kContextOffset, @@ -1481,7 +1481,7 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { // preserved by the finally block. Call the finally block and then // rethrow the exception if it returns. __ Call(&finally_entry); - __ Push(result_register()); + __ push(result_register()); __ CallRuntime(Runtime::kReThrow, 1); // Finally block implementation. diff --git a/chromium/v8/src/full-codegen.h b/chromium/v8/src/full-codegen.h index af63aedfbff..a9db54e32c1 100644 --- a/chromium/v8/src/full-codegen.h +++ b/chromium/v8/src/full-codegen.h @@ -31,14 +31,11 @@ #include "v8.h" #include "allocation.h" -#include "assert-scope.h" #include "ast.h" #include "code-stubs.h" #include "codegen.h" #include "compiler.h" #include "data-flow.h" -#include "globals.h" -#include "objects.h" namespace v8 { namespace internal { @@ -139,64 +136,7 @@ class FullCodeGenerator: public AstVisitor { #error Unsupported target architecture. #endif - class BackEdgeTableIterator { - public: - explicit BackEdgeTableIterator(Code* unoptimized) { - ASSERT(unoptimized->kind() == Code::FUNCTION); - instruction_start_ = unoptimized->instruction_start(); - cursor_ = instruction_start_ + unoptimized->back_edge_table_offset(); - ASSERT(cursor_ < instruction_start_ + unoptimized->instruction_size()); - table_length_ = Memory::uint32_at(cursor_); - cursor_ += kTableLengthSize; - end_ = cursor_ + table_length_ * kEntrySize; - } - - bool Done() { return cursor_ >= end_; } - - void Next() { - ASSERT(!Done()); - cursor_ += kEntrySize; - } - - BailoutId ast_id() { - ASSERT(!Done()); - return BailoutId(static_cast<int>( - Memory::uint32_at(cursor_ + kAstIdOffset))); - } - - uint32_t loop_depth() { - ASSERT(!Done()); - return Memory::uint32_at(cursor_ + kLoopDepthOffset); - } - - uint32_t pc_offset() { - ASSERT(!Done()); - return Memory::uint32_at(cursor_ + kPcOffsetOffset); - } - - Address pc() { - ASSERT(!Done()); - return instruction_start_ + pc_offset(); - } - - uint32_t table_length() { return table_length_; } - - private: - static const int kTableLengthSize = kIntSize; - static const int kAstIdOffset = 0 * kIntSize; - static const int kPcOffsetOffset = 1 * kIntSize; - static const int kLoopDepthOffset = 2 * kIntSize; - static const int kEntrySize = 3 * kIntSize; - - Address cursor_; - Address end_; - Address instruction_start_; - uint32_t table_length_; - DisallowHeapAllocation no_gc_while_iterating_over_raw_addresses_; - - DISALLOW_COPY_AND_ASSIGN(BackEdgeTableIterator); - }; - + static const int kBackEdgeEntrySize = 3 * kIntSize; private: class Breakable; @@ -685,6 +625,8 @@ class FullCodeGenerator: public AstVisitor { AST_NODE_LIST(DECLARE_VISIT) #undef DECLARE_VISIT + void EmitUnaryOperation(UnaryOperation* expr, const char* comment); + void VisitComma(BinaryOperation* expr); void VisitLogicalExpression(BinaryOperation* expr); void VisitArithmeticExpression(BinaryOperation* expr); diff --git a/chromium/v8/src/global-handles.cc b/chromium/v8/src/global-handles.cc index 5df9dd4c6c7..41771e6db41 100644 --- a/chromium/v8/src/global-handles.cc +++ b/chromium/v8/src/global-handles.cc @@ -1019,68 +1019,4 @@ void GlobalHandles::ComputeObjectGroupsAndImplicitReferences() { } -EternalHandles::EternalHandles() : size_(0) { - STATIC_ASSERT(v8::kUninitializedEternalIndex == kInvalidIndex); - for (unsigned i = 0; i < ARRAY_SIZE(singleton_handles_); i++) { - singleton_handles_[i] = kInvalidIndex; - } -} - - -EternalHandles::~EternalHandles() { - for (int i = 0; i < blocks_.length(); i++) delete[] blocks_[i]; -} - - -void EternalHandles::IterateAllRoots(ObjectVisitor* visitor) { - int limit = size_; - for (int i = 0; i < blocks_.length(); i++) { - ASSERT(limit > 0); - Object** block = blocks_[i]; - visitor->VisitPointers(block, block + Min(limit, kSize)); - limit -= kSize; - } -} - - -void EternalHandles::IterateNewSpaceRoots(ObjectVisitor* visitor) { - for (int i = 0; i < new_space_indices_.length(); i++) { - visitor->VisitPointer(GetLocation(new_space_indices_[i])); - } -} - - -void EternalHandles::PostGarbageCollectionProcessing(Heap* heap) { - int last = 0; - for (int i = 0; i < new_space_indices_.length(); i++) { - int index = new_space_indices_[i]; - if (heap->InNewSpace(*GetLocation(index))) { - new_space_indices_[last++] = index; - } - } - new_space_indices_.Rewind(last); -} - - -int EternalHandles::Create(Isolate* isolate, Object* object) { - if (object == NULL) return kInvalidIndex; - ASSERT_NE(isolate->heap()->the_hole_value(), object); - int block = size_ >> kShift; - int offset = size_ & kMask; - // need to resize - if (offset == 0) { - Object** next_block = new Object*[kSize]; - Object* the_hole = isolate->heap()->the_hole_value(); - MemsetPointer(next_block, the_hole, kSize); - blocks_.Add(next_block); - } - ASSERT_EQ(isolate->heap()->the_hole_value(), blocks_[block][offset]); - blocks_[block][offset] = object; - if (isolate->heap()->InNewSpace(object)) { - new_space_indices_.Add(size_); - } - return size_++; -} - - } } // namespace v8::internal diff --git a/chromium/v8/src/global-handles.h b/chromium/v8/src/global-handles.h index 5a4ad13e2f5..cd75133a243 100644 --- a/chromium/v8/src/global-handles.h +++ b/chromium/v8/src/global-handles.h @@ -31,7 +31,6 @@ #include "../include/v8.h" #include "../include/v8-profiler.h" -#include "handles.h" #include "list.h" #include "v8utils.h" @@ -332,76 +331,6 @@ class GlobalHandles { }; -class EternalHandles { - public: - enum SingletonHandle { - I18N_TEMPLATE_ONE, - I18N_TEMPLATE_TWO, - - NUMBER_OF_SINGLETON_HANDLES - }; - - EternalHandles(); - ~EternalHandles(); - - int NumberOfHandles() { return size_; } - - // Create an EternalHandle, returning the index. - int Create(Isolate* isolate, Object* object); - - // Grab the handle for an existing EternalHandle. - inline Handle<Object> Get(int index) { - return Handle<Object>(GetLocation(index)); - } - - // Grab the handle for an existing SingletonHandle. - inline Handle<Object> GetSingleton(SingletonHandle singleton) { - ASSERT(Exists(singleton)); - return Get(singleton_handles_[singleton]); - } - - // Checks whether a SingletonHandle has been assigned. - inline bool Exists(SingletonHandle singleton) { - return singleton_handles_[singleton] != kInvalidIndex; - } - - // Assign a SingletonHandle to an empty slot and returns the handle. - Handle<Object> CreateSingleton(Isolate* isolate, - Object* object, - SingletonHandle singleton) { - ASSERT(singleton_handles_[singleton] == kInvalidIndex); - singleton_handles_[singleton] = Create(isolate, object); - return Get(singleton_handles_[singleton]); - } - - // Iterates over all handles. - void IterateAllRoots(ObjectVisitor* visitor); - // Iterates over all handles which might be in new space. - void IterateNewSpaceRoots(ObjectVisitor* visitor); - // Rebuilds new space list. - void PostGarbageCollectionProcessing(Heap* heap); - - private: - static const int kInvalidIndex = -1; - static const int kShift = 8; - static const int kSize = 1 << kShift; - static const int kMask = 0xff; - - // Gets the slot for an index - inline Object** GetLocation(int index) { - ASSERT(index >= 0 && index < size_); - return &blocks_[index >> kShift][index & kMask]; - } - - int size_; - List<Object**> blocks_; - List<int> new_space_indices_; - int singleton_handles_[NUMBER_OF_SINGLETON_HANDLES]; - - DISALLOW_COPY_AND_ASSIGN(EternalHandles); -}; - - } } // namespace v8::internal #endif // V8_GLOBAL_HANDLES_H_ diff --git a/chromium/v8/src/harmony-array.js b/chromium/v8/src/harmony-array.js deleted file mode 100644 index e440299ff61..00000000000 --- a/chromium/v8/src/harmony-array.js +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -// This file relies on the fact that the following declaration has been made -// in runtime.js: -// var $Array = global.Array; - -// ------------------------------------------------------------------- - -// ES6 draft 07-15-13, section 15.4.3.23 -function ArrayFind(predicate /* thisArg */) { // length == 1 - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["Array.prototype.find"]); - } - - var array = ToObject(this); - var length = ToInteger(array.length); - - if (!IS_SPEC_FUNCTION(predicate)) { - throw MakeTypeError('called_non_callable', [predicate]); - } - - var thisArg; - if (%_ArgumentsLength() > 1) { - thisArg = %_Arguments(1); - } - - if (IS_NULL_OR_UNDEFINED(thisArg)) { - thisArg = %GetDefaultReceiver(predicate) || thisArg; - } else if (!IS_SPEC_OBJECT(thisArg) && %IsClassicModeFunction(predicate)) { - thisArg = ToObject(thisArg); - } - - for (var i = 0; i < length; i++) { - if (i in array) { - var element = array[i]; - if (%_CallFunction(thisArg, element, i, array, predicate)) { - return element; - } - } - } - - return; -} - - -// ES6 draft 07-15-13, section 15.4.3.24 -function ArrayFindIndex(predicate /* thisArg */) { // length == 1 - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["Array.prototype.findIndex"]); - } - - var array = ToObject(this); - var length = ToInteger(array.length); - - if (!IS_SPEC_FUNCTION(predicate)) { - throw MakeTypeError('called_non_callable', [predicate]); - } - - var thisArg; - if (%_ArgumentsLength() > 1) { - thisArg = %_Arguments(1); - } - - if (IS_NULL_OR_UNDEFINED(thisArg)) { - thisArg = %GetDefaultReceiver(predicate) || thisArg; - } else if (!IS_SPEC_OBJECT(thisArg) && %IsClassicModeFunction(predicate)) { - thisArg = ToObject(thisArg); - } - - for (var i = 0; i < length; i++) { - if (i in array) { - var element = array[i]; - if (%_CallFunction(thisArg, element, i, array, predicate)) { - return i; - } - } - } - - return -1; -} - - -// ------------------------------------------------------------------- - -function HarmonyArrayExtendArrayPrototype() { - %CheckIsBootstrapping(); - - // Set up the non-enumerable functions on the Array prototype object. - InstallFunctions($Array.prototype, DONT_ENUM, $Array( - "find", ArrayFind, - "findIndex", ArrayFindIndex - )); -} - -HarmonyArrayExtendArrayPrototype();
\ No newline at end of file diff --git a/chromium/v8/src/heap-snapshot-generator.cc b/chromium/v8/src/heap-snapshot-generator.cc index 1c8a7b3dc4d..9f9f84a01dc 100644 --- a/chromium/v8/src/heap-snapshot-generator.cc +++ b/chromium/v8/src/heap-snapshot-generator.cc @@ -369,12 +369,6 @@ const SnapshotObjectId HeapObjectsMap::kFirstAvailableObjectId = HeapObjectsMap::kGcRootsFirstSubrootId + VisitorSynchronization::kNumberOfSyncTags * HeapObjectsMap::kObjectIdStep; - -static bool AddressesMatch(void* key1, void* key2) { - return key1 == key2; -} - - HeapObjectsMap::HeapObjectsMap(Heap* heap) : next_id_(kFirstAvailableObjectId), entries_map_(AddressesMatch), @@ -399,20 +393,19 @@ void HeapObjectsMap::MoveObject(Address from, Address to) { ASSERT(to != NULL); ASSERT(from != NULL); if (from == to) return; - void* from_value = entries_map_.Remove(from, ComputePointerHash(from)); + void* from_value = entries_map_.Remove(from, AddressHash(from)); if (from_value == NULL) { // It may occur that some untracked object moves to an address X and there // is a tracked object at that address. In this case we should remove the // entry as we know that the object has died. - void* to_value = entries_map_.Remove(to, ComputePointerHash(to)); + void* to_value = entries_map_.Remove(to, AddressHash(to)); if (to_value != NULL) { int to_entry_info_index = static_cast<int>(reinterpret_cast<intptr_t>(to_value)); entries_.at(to_entry_info_index).addr = NULL; } } else { - HashMap::Entry* to_entry = entries_map_.Lookup(to, ComputePointerHash(to), - true); + HashMap::Entry* to_entry = entries_map_.Lookup(to, AddressHash(to), true); if (to_entry->value != NULL) { // We found the existing entry with to address for an old object. // Without this operation we will have two EntryInfo's with the same @@ -432,8 +425,7 @@ void HeapObjectsMap::MoveObject(Address from, Address to) { SnapshotObjectId HeapObjectsMap::FindEntry(Address addr) { - HashMap::Entry* entry = entries_map_.Lookup(addr, ComputePointerHash(addr), - false); + HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), false); if (entry == NULL) return 0; int entry_index = static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); EntryInfo& entry_info = entries_.at(entry_index); @@ -445,8 +437,7 @@ SnapshotObjectId HeapObjectsMap::FindEntry(Address addr) { SnapshotObjectId HeapObjectsMap::FindOrAddEntry(Address addr, unsigned int size) { ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy()); - HashMap::Entry* entry = entries_map_.Lookup(addr, ComputePointerHash(addr), - true); + HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), true); if (entry->value != NULL) { int entry_index = static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); @@ -541,14 +532,13 @@ void HeapObjectsMap::RemoveDeadEntries() { } entries_.at(first_free_entry).accessed = false; HashMap::Entry* entry = entries_map_.Lookup( - entry_info.addr, ComputePointerHash(entry_info.addr), false); + entry_info.addr, AddressHash(entry_info.addr), false); ASSERT(entry); entry->value = reinterpret_cast<void*>(first_free_entry); ++first_free_entry; } else { if (entry_info.addr) { - entries_map_.Remove(entry_info.addr, - ComputePointerHash(entry_info.addr)); + entries_map_.Remove(entry_info.addr, AddressHash(entry_info.addr)); } } } diff --git a/chromium/v8/src/heap-snapshot-generator.h b/chromium/v8/src/heap-snapshot-generator.h index cea995820f7..31d808856d1 100644 --- a/chromium/v8/src/heap-snapshot-generator.h +++ b/chromium/v8/src/heap-snapshot-generator.h @@ -266,6 +266,16 @@ class HeapObjectsMap { void UpdateHeapObjectsMap(); void RemoveDeadEntries(); + static bool AddressesMatch(void* key1, void* key2) { + return key1 == key2; + } + + static uint32_t AddressHash(Address addr) { + return ComputeIntegerHash( + static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr)), + v8::internal::kZeroHashSeed); + } + SnapshotObjectId next_id_; HashMap entries_map_; List<EntryInfo> entries_; diff --git a/chromium/v8/src/heap.cc b/chromium/v8/src/heap.cc index 9d8a6fad995..c2a2707602e 100644 --- a/chromium/v8/src/heap.cc +++ b/chromium/v8/src/heap.cc @@ -703,16 +703,6 @@ bool Heap::CollectGarbage(AllocationSpace space, } -int Heap::NotifyContextDisposed() { - if (FLAG_parallel_recompilation) { - // Flush the queued recompilation tasks. - isolate()->optimizing_compiler_thread()->Flush(); - } - flush_monomorphic_ics_ = true; - return ++contexts_disposed_; -} - - void Heap::PerformScavenge() { GCTracer tracer(this, NULL, NULL); if (incremental_marking()->IsStopped()) { @@ -1024,8 +1014,6 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector, } gc_post_processing_depth_--; - isolate_->eternal_handles()->PostGarbageCollectionProcessing(this); - // Update relocatables. Relocatable::PostGarbageCollectionProcessing(); @@ -2018,6 +2006,7 @@ class ScavengingVisitor : public StaticVisitorBase { private: enum ObjectContents { DATA_OBJECT, POINTER_OBJECT }; + enum SizeRestriction { SMALL, UNKNOWN_SIZE }; static void RecordCopiedObject(Heap* heap, HeapObject* obj) { bool should_record = false; @@ -2069,12 +2058,15 @@ class ScavengingVisitor : public StaticVisitorBase { } - template<ObjectContents object_contents, int alignment> + template<ObjectContents object_contents, + SizeRestriction size_restriction, + int alignment> static inline void EvacuateObject(Map* map, HeapObject** slot, HeapObject* object, int object_size) { - SLOW_ASSERT(object_size <= Page::kMaxNonCodeHeapObjectSize); + SLOW_ASSERT((size_restriction != SMALL) || + (object_size <= Page::kMaxNonCodeHeapObjectSize)); SLOW_ASSERT(object->Size() == object_size); int allocation_size = object_size; @@ -2087,11 +2079,17 @@ class ScavengingVisitor : public StaticVisitorBase { if (heap->ShouldBePromoted(object->address(), object_size)) { MaybeObject* maybe_result; - if (object_contents == DATA_OBJECT) { - maybe_result = heap->old_data_space()->AllocateRaw(allocation_size); + if ((size_restriction != SMALL) && + (allocation_size > Page::kMaxNonCodeHeapObjectSize)) { + maybe_result = heap->lo_space()->AllocateRaw(allocation_size, + NOT_EXECUTABLE); } else { - maybe_result = - heap->old_pointer_space()->AllocateRaw(allocation_size); + if (object_contents == DATA_OBJECT) { + maybe_result = heap->old_data_space()->AllocateRaw(allocation_size); + } else { + maybe_result = + heap->old_pointer_space()->AllocateRaw(allocation_size); + } } Object* result = NULL; // Initialization to please compiler. @@ -2165,8 +2163,10 @@ class ScavengingVisitor : public StaticVisitorBase { HeapObject** slot, HeapObject* object) { int object_size = FixedArray::BodyDescriptor::SizeOf(map, object); - EvacuateObject<POINTER_OBJECT, kObjectAlignment>( - map, slot, object, object_size); + EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(map, + slot, + object, + object_size); } @@ -2175,8 +2175,11 @@ class ScavengingVisitor : public StaticVisitorBase { HeapObject* object) { int length = reinterpret_cast<FixedDoubleArray*>(object)->length(); int object_size = FixedDoubleArray::SizeFor(length); - EvacuateObject<DATA_OBJECT, kDoubleAlignment>( - map, slot, object, object_size); + EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kDoubleAlignment>( + map, + slot, + object, + object_size); } @@ -2184,7 +2187,7 @@ class ScavengingVisitor : public StaticVisitorBase { HeapObject** slot, HeapObject* object) { int object_size = reinterpret_cast<ByteArray*>(object)->ByteArraySize(); - EvacuateObject<DATA_OBJECT, kObjectAlignment>( + EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>( map, slot, object, object_size); } @@ -2194,7 +2197,7 @@ class ScavengingVisitor : public StaticVisitorBase { HeapObject* object) { int object_size = SeqOneByteString::cast(object)-> SeqOneByteStringSize(map->instance_type()); - EvacuateObject<DATA_OBJECT, kObjectAlignment>( + EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>( map, slot, object, object_size); } @@ -2204,7 +2207,7 @@ class ScavengingVisitor : public StaticVisitorBase { HeapObject* object) { int object_size = SeqTwoByteString::cast(object)-> SeqTwoByteStringSize(map->instance_type()); - EvacuateObject<DATA_OBJECT, kObjectAlignment>( + EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>( map, slot, object, object_size); } @@ -2248,7 +2251,7 @@ class ScavengingVisitor : public StaticVisitorBase { } int object_size = ConsString::kSize; - EvacuateObject<POINTER_OBJECT, kObjectAlignment>( + EvacuateObject<POINTER_OBJECT, SMALL, kObjectAlignment>( map, slot, object, object_size); } @@ -2259,7 +2262,7 @@ class ScavengingVisitor : public StaticVisitorBase { static inline void VisitSpecialized(Map* map, HeapObject** slot, HeapObject* object) { - EvacuateObject<object_contents, kObjectAlignment>( + EvacuateObject<object_contents, SMALL, kObjectAlignment>( map, slot, object, object_size); } @@ -2267,7 +2270,7 @@ class ScavengingVisitor : public StaticVisitorBase { HeapObject** slot, HeapObject* object) { int object_size = map->instance_size(); - EvacuateObject<object_contents, kObjectAlignment>( + EvacuateObject<object_contents, SMALL, kObjectAlignment>( map, slot, object, object_size); } }; @@ -3215,6 +3218,9 @@ bool Heap::CreateInitialObjects() { } set_observed_symbol(Symbol::cast(obj)); + set_i18n_template_one(the_hole_value()); + set_i18n_template_two(the_hole_value()); + // Handling of script id generation is in Factory::NewScript. set_last_script_id(Smi::FromInt(v8::Script::kNoScriptId)); @@ -3263,12 +3269,6 @@ bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) { } -bool Heap::RootCanBeTreatedAsConstant(RootListIndex root_index) { - return !RootCanBeWrittenAfterInitialization(root_index) && - !InNewSpace(roots_array_start()[root_index]); -} - - Object* RegExpResultsCache::Lookup(Heap* heap, String* key_string, Object* key_pattern, @@ -4481,8 +4481,7 @@ void Heap::InitializeJSObjectFromMap(JSObject* obj, } -MaybeObject* Heap::AllocateJSObjectFromMap( - Map* map, PretenureFlag pretenure, bool allocate_properties) { +MaybeObject* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) { // JSFunctions should be allocated using AllocateFunction to be // properly initialized. ASSERT(map->instance_type() != JS_FUNCTION_TYPE); @@ -4493,15 +4492,11 @@ MaybeObject* Heap::AllocateJSObjectFromMap( ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE); // Allocate the backing storage for the properties. - FixedArray* properties; - if (allocate_properties) { - int prop_size = map->InitialPropertiesLength(); - ASSERT(prop_size >= 0); - { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, pretenure); - if (!maybe_properties->To(&properties)) return maybe_properties; - } - } else { - properties = empty_fixed_array(); + int prop_size = map->InitialPropertiesLength(); + ASSERT(prop_size >= 0); + Object* properties; + { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, pretenure); + if (!maybe_properties->ToObject(&properties)) return maybe_properties; } // Allocate the JSObject. @@ -4513,15 +4508,17 @@ MaybeObject* Heap::AllocateJSObjectFromMap( if (!maybe_obj->To(&obj)) return maybe_obj; // Initialize the JSObject. - InitializeJSObjectFromMap(JSObject::cast(obj), properties, map); + InitializeJSObjectFromMap(JSObject::cast(obj), + FixedArray::cast(properties), + map); ASSERT(JSObject::cast(obj)->HasFastElements() || JSObject::cast(obj)->HasExternalArrayElements()); return obj; } -MaybeObject* Heap::AllocateJSObjectFromMapWithAllocationSite( - Map* map, Handle<AllocationSite> allocation_site) { +MaybeObject* Heap::AllocateJSObjectFromMapWithAllocationSite(Map* map, + Handle<AllocationSite> allocation_site) { // JSFunctions should be allocated using AllocateFunction to be // properly initialized. ASSERT(map->instance_type() != JS_FUNCTION_TYPE); @@ -4534,9 +4531,9 @@ MaybeObject* Heap::AllocateJSObjectFromMapWithAllocationSite( // Allocate the backing storage for the properties. int prop_size = map->InitialPropertiesLength(); ASSERT(prop_size >= 0); - FixedArray* properties; + Object* properties; { MaybeObject* maybe_properties = AllocateFixedArray(prop_size); - if (!maybe_properties->To(&properties)) return maybe_properties; + if (!maybe_properties->ToObject(&properties)) return maybe_properties; } // Allocate the JSObject. @@ -4548,7 +4545,9 @@ MaybeObject* Heap::AllocateJSObjectFromMapWithAllocationSite( if (!maybe_obj->To(&obj)) return maybe_obj; // Initialize the JSObject. - InitializeJSObjectFromMap(JSObject::cast(obj), properties, map); + InitializeJSObjectFromMap(JSObject::cast(obj), + FixedArray::cast(properties), + map); ASSERT(JSObject::cast(obj)->HasFastElements()); return obj; } @@ -6609,14 +6608,6 @@ void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) { } v->Synchronize(VisitorSynchronization::kGlobalHandles); - // Iterate over eternal handles. - if (mode == VISIT_ALL_IN_SCAVENGE) { - isolate_->eternal_handles()->IterateNewSpaceRoots(v); - } else { - isolate_->eternal_handles()->IterateAllRoots(v); - } - v->Synchronize(VisitorSynchronization::kEternalHandles); - // Iterate over pointers being held by inactive threads. isolate_->thread_manager()->Iterate(v); v->Synchronize(VisitorSynchronization::kThreadManager); diff --git a/chromium/v8/src/heap.h b/chromium/v8/src/heap.h index 78c0e5b26b4..672b8c16325 100644 --- a/chromium/v8/src/heap.h +++ b/chromium/v8/src/heap.h @@ -189,7 +189,9 @@ namespace internal { V(Symbol, elements_transition_symbol, ElementsTransitionSymbol) \ V(SeededNumberDictionary, empty_slow_element_dictionary, \ EmptySlowElementDictionary) \ - V(Symbol, observed_symbol, ObservedSymbol) + V(Symbol, observed_symbol, ObservedSymbol) \ + V(HeapObject, i18n_template_one, I18nTemplateOne) \ + V(HeapObject, i18n_template_two, I18nTemplateTwo) #define ROOT_LIST(V) \ STRONG_ROOT_LIST(V) \ @@ -736,7 +738,7 @@ class Heap { // failed. // Please note this does not perform a garbage collection. MUST_USE_RESULT MaybeObject* AllocateJSObjectFromMap( - Map* map, PretenureFlag pretenure = NOT_TENURED, bool alloc_props = true); + Map* map, PretenureFlag pretenure = NOT_TENURED); MUST_USE_RESULT MaybeObject* AllocateJSObjectFromMapWithAllocationSite( Map* map, Handle<AllocationSite> allocation_site); @@ -1254,7 +1256,10 @@ class Heap { void EnsureHeapIsIterable(); // Notify the heap that a context has been disposed. - int NotifyContextDisposed(); + int NotifyContextDisposed() { + flush_monomorphic_ics_ = true; + return ++contexts_disposed_; + } // Utility to invoke the scavenger. This is needed in test code to // ensure correct callback for weak global handles. @@ -1297,6 +1302,12 @@ class Heap { ASSERT((callback == NULL) ^ (global_gc_epilogue_callback_ == NULL)); global_gc_epilogue_callback_ = callback; } + void SetI18nTemplateOne(ObjectTemplateInfo* tmpl) { + set_i18n_template_one(tmpl); + } + void SetI18nTemplateTwo(ObjectTemplateInfo* tmpl) { + set_i18n_template_two(tmpl); + } // Heap root getters. We have versions with and without type::cast() here. // You can't use type::cast during GC because the assert fails. @@ -1615,8 +1626,6 @@ class Heap { // Generated code can embed direct references to non-writable roots if // they are in new space. static bool RootCanBeWrittenAfterInitialization(RootListIndex root_index); - // Generated code can treat direct references to this root as constant. - bool RootCanBeTreatedAsConstant(RootListIndex root_index); MUST_USE_RESULT MaybeObject* NumberToString( Object* number, bool check_number_string_cache = true, diff --git a/chromium/v8/src/hydrogen-escape-analysis.cc b/chromium/v8/src/hydrogen-escape-analysis.cc index 0359678ef95..961bb94e9c1 100644 --- a/chromium/v8/src/hydrogen-escape-analysis.cc +++ b/chromium/v8/src/hydrogen-escape-analysis.cc @@ -63,234 +63,4 @@ void HEscapeAnalysisPhase::CollectCapturedValues() { } -HCapturedObject* HEscapeAnalysisPhase::NewState(HInstruction* previous) { - Zone* zone = graph()->zone(); - HCapturedObject* state = new(zone) HCapturedObject(number_of_values_, zone); - state->InsertAfter(previous); - return state; -} - - -// Create a new state for replacing HAllocate instructions. -HCapturedObject* HEscapeAnalysisPhase::NewStateForAllocation( - HInstruction* previous) { - HConstant* undefined = graph()->GetConstantUndefined(); - HCapturedObject* state = NewState(previous); - for (int index = 0; index < number_of_values_; index++) { - state->SetOperandAt(index, undefined); - } - return state; -} - - -// Create a new state full of phis for loop header entries. -HCapturedObject* HEscapeAnalysisPhase::NewStateForLoopHeader( - HInstruction* previous, HCapturedObject* old_state) { - HBasicBlock* block = previous->block(); - HCapturedObject* state = NewState(previous); - for (int index = 0; index < number_of_values_; index++) { - HValue* operand = old_state->OperandAt(index); - HPhi* phi = NewPhiAndInsert(block, operand, index); - state->SetOperandAt(index, phi); - } - return state; -} - - -// Create a new state by copying an existing one. -HCapturedObject* HEscapeAnalysisPhase::NewStateCopy( - HInstruction* previous, HCapturedObject* old_state) { - HCapturedObject* state = NewState(previous); - for (int index = 0; index < number_of_values_; index++) { - HValue* operand = old_state->OperandAt(index); - state->SetOperandAt(index, operand); - } - return state; -} - - -// Insert a newly created phi into the given block and fill all incoming -// edges with the given value. -HPhi* HEscapeAnalysisPhase::NewPhiAndInsert( - HBasicBlock* block, HValue* incoming_value, int index) { - Zone* zone = graph()->zone(); - HPhi* phi = new(zone) HPhi(HPhi::kInvalidMergedIndex, zone); - for (int i = 0; i < block->predecessors()->length(); i++) { - phi->AddInput(incoming_value); - } - block->AddPhi(phi); - return phi; -} - - -// Performs a forward data-flow analysis of all loads and stores on the -// given captured allocation. This uses a reverse post-order iteration -// over affected basic blocks. All non-escaping instructions are handled -// and replaced during the analysis. -void HEscapeAnalysisPhase::AnalyzeDataFlow(HInstruction* allocate) { - HBasicBlock* allocate_block = allocate->block(); - block_states_.AddBlock(NULL, graph()->blocks()->length(), zone()); - - // Iterate all blocks starting with the allocation block, since the - // allocation cannot dominate blocks that come before. - int start = allocate_block->block_id(); - for (int i = start; i < graph()->blocks()->length(); i++) { - HBasicBlock* block = graph()->blocks()->at(i); - HCapturedObject* state = StateAt(block); - - // Skip blocks that are not dominated by the captured allocation. - if (!allocate_block->Dominates(block) && allocate_block != block) continue; - if (FLAG_trace_escape_analysis) { - PrintF("Analyzing data-flow in B%d\n", block->block_id()); - } - - // Go through all instructions of the current block. - for (HInstructionIterator it(block); !it.Done(); it.Advance()) { - HInstruction* instr = it.Current(); - switch (instr->opcode()) { - case HValue::kAllocate: { - if (instr != allocate) continue; - state = NewStateForAllocation(allocate); - break; - } - case HValue::kLoadNamedField: { - HLoadNamedField* load = HLoadNamedField::cast(instr); - int index = load->access().offset() / kPointerSize; - if (load->object() != allocate) continue; - ASSERT(load->access().IsInobject()); - HValue* replacement = state->OperandAt(index); - load->DeleteAndReplaceWith(replacement); - if (FLAG_trace_escape_analysis) { - PrintF("Replacing load #%d with #%d (%s)\n", instr->id(), - replacement->id(), replacement->Mnemonic()); - } - break; - } - case HValue::kStoreNamedField: { - HStoreNamedField* store = HStoreNamedField::cast(instr); - int index = store->access().offset() / kPointerSize; - if (store->object() != allocate) continue; - ASSERT(store->access().IsInobject()); - state = NewStateCopy(store, state); - state->SetOperandAt(index, store->value()); - if (store->has_transition()) { - state->SetOperandAt(0, store->transition()); - } - store->DeleteAndReplaceWith(NULL); - if (FLAG_trace_escape_analysis) { - PrintF("Replacing store #%d%s\n", instr->id(), - store->has_transition() ? " (with transition)" : ""); - } - break; - } - case HValue::kSimulate: { - HSimulate* simulate = HSimulate::cast(instr); - // TODO(mstarzinger): This doesn't track deltas for values on the - // operand stack yet. Find a repro test case and fix this. - for (int i = 0; i < simulate->OperandCount(); i++) { - if (simulate->OperandAt(i) != allocate) continue; - simulate->SetOperandAt(i, state); - } - break; - } - case HValue::kArgumentsObject: - case HValue::kCapturedObject: { - for (int i = 0; i < instr->OperandCount(); i++) { - if (instr->OperandAt(i) != allocate) continue; - instr->SetOperandAt(i, state); - } - break; - } - case HValue::kCheckHeapObject: { - HCheckHeapObject* check = HCheckHeapObject::cast(instr); - if (check->value() != allocate) continue; - check->DeleteAndReplaceWith(NULL); - break; - } - case HValue::kCheckMaps: { - HCheckMaps* mapcheck = HCheckMaps::cast(instr); - if (mapcheck->value() != allocate) continue; - // TODO(mstarzinger): This approach breaks if the tracked map value - // is not a HConstant. Find a repro test case and fix this. - for (HUseIterator it(mapcheck->uses()); !it.Done(); it.Advance()) { - if (!it.value()->IsLoadNamedField()) continue; - HLoadNamedField* load = HLoadNamedField::cast(it.value()); - ASSERT(load->typecheck() == mapcheck); - load->ClearTypeCheck(); - } - ASSERT(mapcheck->HasNoUses()); - - mapcheck->DeleteAndReplaceWith(NULL); - break; - } - default: - // Nothing to see here, move along ... - break; - } - } - - // Propagate the block state forward to all successor blocks. - for (int i = 0; i < block->end()->SuccessorCount(); i++) { - HBasicBlock* succ = block->end()->SuccessorAt(i); - if (!allocate_block->Dominates(succ)) continue; - if (succ->predecessors()->length() == 1) { - // Case 1: This is the only predecessor, just reuse state. - SetStateAt(succ, state); - } else if (StateAt(succ) == NULL && succ->IsLoopHeader()) { - // Case 2: This is a state that enters a loop header, be - // pessimistic about loop headers, add phis for all values. - SetStateAt(succ, NewStateForLoopHeader(succ->first(), state)); - } else if (StateAt(succ) == NULL) { - // Case 3: This is the first state propagated forward to the - // successor, leave a copy of the current state. - SetStateAt(succ, NewStateCopy(succ->first(), state)); - } else { - // Case 4: This is a state that needs merging with previously - // propagated states, potentially introducing new phis lazily or - // adding values to existing phis. - HCapturedObject* succ_state = StateAt(succ); - for (int index = 0; index < number_of_values_; index++) { - HValue* operand = state->OperandAt(index); - HValue* succ_operand = succ_state->OperandAt(index); - if (succ_operand->IsPhi() && succ_operand->block() == succ) { - // Phi already exists, add operand. - HPhi* phi = HPhi::cast(succ_operand); - phi->SetOperandAt(succ->PredecessorIndexOf(block), operand); - } else if (succ_operand != operand) { - // Phi does not exist, introduce one. - HPhi* phi = NewPhiAndInsert(succ, succ_operand, index); - phi->SetOperandAt(succ->PredecessorIndexOf(block), operand); - succ_state->SetOperandAt(index, phi); - } - } - } - } - } - - // All uses have been handled. - ASSERT(allocate->HasNoUses()); - allocate->DeleteAndReplaceWith(NULL); -} - - -void HEscapeAnalysisPhase::PerformScalarReplacement() { - for (int i = 0; i < captured_.length(); i++) { - HAllocate* allocate = HAllocate::cast(captured_.at(i)); - - // Compute number of scalar values and start with clean slate. - if (!allocate->size()->IsInteger32Constant()) continue; - int size_in_bytes = allocate->size()->GetInteger32Constant(); - number_of_values_ = size_in_bytes / kPointerSize; - block_states_.Clear(); - - // Perform actual analysis steps. - AnalyzeDataFlow(allocate); - - cumulative_values_ += number_of_values_; - ASSERT(allocate->HasNoUses()); - ASSERT(!allocate->IsLinked()); - } -} - - } } // namespace v8::internal diff --git a/chromium/v8/src/hydrogen-escape-analysis.h b/chromium/v8/src/hydrogen-escape-analysis.h index 123da214e34..6ba6e823c54 100644 --- a/chromium/v8/src/hydrogen-escape-analysis.h +++ b/chromium/v8/src/hydrogen-escape-analysis.h @@ -38,48 +38,17 @@ namespace internal { class HEscapeAnalysisPhase : public HPhase { public: explicit HEscapeAnalysisPhase(HGraph* graph) - : HPhase("H_Escape analysis", graph), - captured_(0, zone()), - number_of_values_(0), - cumulative_values_(0), - block_states_(graph->blocks()->length(), zone()) { } + : HPhase("H_Escape analysis", graph), captured_(0, zone()) { } void Run() { CollectCapturedValues(); - PerformScalarReplacement(); } private: void CollectCapturedValues(); void CollectIfNoEscapingUses(HInstruction* instr); - void PerformScalarReplacement(); - void AnalyzeDataFlow(HInstruction* instr); - HCapturedObject* NewState(HInstruction* prev); - HCapturedObject* NewStateForAllocation(HInstruction* prev); - HCapturedObject* NewStateForLoopHeader(HInstruction* prev, HCapturedObject*); - HCapturedObject* NewStateCopy(HInstruction* prev, HCapturedObject* state); - - HPhi* NewPhiAndInsert(HBasicBlock* block, HValue* incoming_value, int index); - - HCapturedObject* StateAt(HBasicBlock* block) { - return block_states_.at(block->block_id()); - } - - void SetStateAt(HBasicBlock* block, HCapturedObject* state) { - block_states_.Set(block->block_id(), state); - } - - // List of allocations captured during collection phase. - ZoneList<HInstruction*> captured_; - - // Number of scalar values tracked during scalar replacement phase. - int number_of_values_; - int cumulative_values_; - - // Map of block IDs to the data-flow state at block entry during the - // scalar replacement phase. - ZoneList<HCapturedObject*> block_states_; + ZoneList<HValue*> captured_; }; diff --git a/chromium/v8/src/hydrogen-instructions.cc b/chromium/v8/src/hydrogen-instructions.cc index a4c54e761e7..d2f16f46acc 100644 --- a/chromium/v8/src/hydrogen-instructions.cc +++ b/chromium/v8/src/hydrogen-instructions.cc @@ -149,6 +149,116 @@ void HValue::AddDependantsToWorklist(HInferRepresentationPhase* h_infer) { } +// This method is recursive but it is guaranteed to terminate because +// RedefinedOperand() always dominates "this". +bool HValue::IsRelationTrue(NumericRelation relation, + HValue* other, + int offset, + int scale) { + if (this == other) { + return scale == 0 && relation.IsExtendable(offset); + } + + // Test the direct relation. + if (IsRelationTrueInternal(relation, other, offset, scale)) return true; + + // If scale is 0 try the reversed relation. + if (scale == 0 && + // TODO(mmassi): do we need the full, recursive IsRelationTrue? + other->IsRelationTrueInternal(relation.Reversed(), this, -offset)) { + return true; + } + + // Try decomposition (but do not accept scaled compounds). + DecompositionResult decomposition; + if (TryDecompose(&decomposition) && + decomposition.scale() == 0 && + decomposition.base()->IsRelationTrue(relation, other, + offset + decomposition.offset(), + scale)) { + return true; + } + + // Pass the request to the redefined value. + HValue* redefined = RedefinedOperand(); + return redefined != NULL && redefined->IsRelationTrue(relation, other, + offset, scale); +} + + +bool HValue::TryGuaranteeRange(HValue* upper_bound) { + RangeEvaluationContext context = RangeEvaluationContext(this, upper_bound); + TryGuaranteeRangeRecursive(&context); + bool result = context.is_range_satisfied(); + if (result) { + context.lower_bound_guarantee()->SetResponsibilityForRange(DIRECTION_LOWER); + context.upper_bound_guarantee()->SetResponsibilityForRange(DIRECTION_UPPER); + } + return result; +} + + +void HValue::TryGuaranteeRangeRecursive(RangeEvaluationContext* context) { + // Check if we already know that this value satisfies the lower bound. + if (context->lower_bound_guarantee() == NULL) { + if (IsRelationTrueInternal(NumericRelation::Ge(), context->lower_bound(), + context->offset(), context->scale())) { + context->set_lower_bound_guarantee(this); + } + } + + // Check if we already know that this value satisfies the upper bound. + if (context->upper_bound_guarantee() == NULL) { + if (IsRelationTrueInternal(NumericRelation::Lt(), context->upper_bound(), + context->offset(), context->scale()) || + (context->scale() == 0 && + context->upper_bound()->IsRelationTrue(NumericRelation::Gt(), + this, -context->offset()))) { + context->set_upper_bound_guarantee(this); + } + } + + if (context->is_range_satisfied()) return; + + // See if our RedefinedOperand() satisfies the constraints. + if (RedefinedOperand() != NULL) { + RedefinedOperand()->TryGuaranteeRangeRecursive(context); + } + if (context->is_range_satisfied()) return; + + // See if the constraints can be satisfied by decomposition. + DecompositionResult decomposition; + if (TryDecompose(&decomposition)) { + context->swap_candidate(&decomposition); + context->candidate()->TryGuaranteeRangeRecursive(context); + context->swap_candidate(&decomposition); + } + if (context->is_range_satisfied()) return; + + // Try to modify this to satisfy the constraint. + + TryGuaranteeRangeChanging(context); +} + + +RangeEvaluationContext::RangeEvaluationContext(HValue* value, HValue* upper) + : lower_bound_(upper->block()->graph()->GetConstant0()), + lower_bound_guarantee_(NULL), + candidate_(value), + upper_bound_(upper), + upper_bound_guarantee_(NULL), + offset_(0), + scale_(0) { +} + + +HValue* RangeEvaluationContext::ConvertGuarantee(HValue* guarantee) { + return guarantee->IsBoundsCheckBaseIndexInformation() + ? HBoundsCheckBaseIndexInformation::cast(guarantee)->bounds_check() + : guarantee; +} + + static int32_t ConvertAndSetOverflow(Representation r, int64_t result, bool* overflow) { @@ -374,6 +484,55 @@ HType HType::TypeFromValue(Handle<Object> value) { } +bool HValue::Dominates(HValue* dominator, HValue* dominated) { + if (dominator->block() != dominated->block()) { + // If they are in different blocks we can use the dominance relation + // between the blocks. + return dominator->block()->Dominates(dominated->block()); + } else { + // Otherwise we must see which instruction comes first, considering + // that phis always precede regular instructions. + if (dominator->IsInstruction()) { + if (dominated->IsInstruction()) { + for (HInstruction* next = HInstruction::cast(dominator)->next(); + next != NULL; + next = next->next()) { + if (next == dominated) return true; + } + return false; + } else if (dominated->IsPhi()) { + return false; + } else { + UNREACHABLE(); + } + } else if (dominator->IsPhi()) { + if (dominated->IsInstruction()) { + return true; + } else { + // We cannot compare which phi comes first. + UNREACHABLE(); + } + } else { + UNREACHABLE(); + } + return false; + } +} + + +bool HValue::TestDominanceUsingProcessedFlag(HValue* dominator, + HValue* dominated) { + if (dominator->block() != dominated->block()) { + return dominator->block()->Dominates(dominated->block()); + } else { + // If both arguments are in the same block we check if dominator is a phi + // or if dominated has not already been processed: in either case we know + // that dominator precedes dominated. + return dominator->IsPhi() || !dominated->CheckFlag(kIDefsProcessingDone); + } +} + + bool HValue::IsDefinedAfter(HBasicBlock* other) const { return block()->block_id() > other->block_id(); } @@ -388,7 +547,7 @@ HUseListNode* HUseListNode::tail() { } -bool HValue::CheckUsesForFlag(Flag f) const { +bool HValue::CheckUsesForFlag(Flag f) { for (HUseIterator it(uses()); !it.Done(); it.Advance()) { if (it.value()->IsSimulate()) continue; if (!it.value()->CheckFlag(f)) return false; @@ -397,7 +556,7 @@ bool HValue::CheckUsesForFlag(Flag f) const { } -bool HValue::HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const { +bool HValue::HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) { bool return_value = false; for (HUseIterator it(uses()); !it.Done(); it.Advance()) { if (it.value()->IsSimulate()) continue; @@ -801,6 +960,58 @@ void HInstruction::Verify() { #endif +HNumericConstraint* HNumericConstraint::AddToGraph( + HValue* constrained_value, + NumericRelation relation, + HValue* related_value, + HInstruction* insertion_point) { + if (insertion_point == NULL) { + if (constrained_value->IsInstruction()) { + insertion_point = HInstruction::cast(constrained_value); + } else if (constrained_value->IsPhi()) { + insertion_point = constrained_value->block()->first(); + } else { + UNREACHABLE(); + } + } + HNumericConstraint* result = + new(insertion_point->block()->zone()) HNumericConstraint( + constrained_value, relation, related_value); + result->InsertAfter(insertion_point); + return result; +} + + +void HNumericConstraint::PrintDataTo(StringStream* stream) { + stream->Add("("); + constrained_value()->PrintNameTo(stream); + stream->Add(" %s ", relation().Mnemonic()); + related_value()->PrintNameTo(stream); + stream->Add(")"); +} + + +HInductionVariableAnnotation* HInductionVariableAnnotation::AddToGraph( + HPhi* phi, + NumericRelation relation, + int operand_index) { + HInductionVariableAnnotation* result = + new(phi->block()->zone()) HInductionVariableAnnotation(phi, relation, + operand_index); + result->InsertAfter(phi->block()->first()); + return result; +} + + +void HInductionVariableAnnotation::PrintDataTo(StringStream* stream) { + stream->Add("("); + RedefinedOperand()->PrintNameTo(stream); + stream->Add(" %s ", relation().Mnemonic()); + induction_base()->PrintNameTo(stream); + stream->Add(")"); +} + + void HDummyUse::PrintDataTo(StringStream* stream) { value()->PrintNameTo(stream); } @@ -827,6 +1038,40 @@ void HBinaryCall::PrintDataTo(StringStream* stream) { } +void HBoundsCheck::TryGuaranteeRangeChanging(RangeEvaluationContext* context) { + if (context->candidate()->ActualValue() != base()->ActualValue() || + context->scale() < scale()) { + return; + } + + // TODO(mmassi) + // Instead of checking for "same basic block" we should check for + // "dominates and postdominates". + if (context->upper_bound() == length() && + context->lower_bound_guarantee() != NULL && + context->lower_bound_guarantee() != this && + context->lower_bound_guarantee()->block() != block() && + offset() < context->offset() && + index_can_increase() && + context->upper_bound_guarantee() == NULL) { + offset_ = context->offset(); + SetResponsibilityForRange(DIRECTION_UPPER); + context->set_upper_bound_guarantee(this); + isolate()->counters()->bounds_checks_eliminated()->Increment(); + } else if (context->upper_bound_guarantee() != NULL && + context->upper_bound_guarantee() != this && + context->upper_bound_guarantee()->block() != block() && + offset() > context->offset() && + index_can_decrease() && + context->lower_bound_guarantee() == NULL) { + offset_ = context->offset(); + SetResponsibilityForRange(DIRECTION_LOWER); + context->set_lower_bound_guarantee(this); + isolate()->counters()->bounds_checks_eliminated()->Increment(); + } +} + + void HBoundsCheck::ApplyIndexChange() { if (skip_check()) return; @@ -874,6 +1119,40 @@ void HBoundsCheck::ApplyIndexChange() { base_ = NULL; offset_ = 0; scale_ = 0; + responsibility_direction_ = DIRECTION_NONE; +} + + +void HBoundsCheck::AddInformativeDefinitions() { + // TODO(mmassi): Executing this code during AddInformativeDefinitions + // is a hack. Move it to some other HPhase. + if (FLAG_array_bounds_checks_elimination) { + if (index()->TryGuaranteeRange(length())) { + set_skip_check(); + } + if (DetectCompoundIndex()) { + HBoundsCheckBaseIndexInformation* base_index_info = + new(block()->graph()->zone()) + HBoundsCheckBaseIndexInformation(this); + base_index_info->InsertAfter(this); + } + } +} + + +bool HBoundsCheck::IsRelationTrueInternal(NumericRelation relation, + HValue* related_value, + int offset, + int scale) { + if (related_value == length()) { + // A HBoundsCheck is smaller than the length it compared against. + return NumericRelation::Lt().CompoundImplies(relation, 0, 0, offset, scale); + } else if (related_value == block()->graph()->GetConstant0()) { + // A HBoundsCheck is greater than or equal to zero. + return NumericRelation::Ge().CompoundImplies(relation, 0, 0, offset, scale); + } else { + return false; + } } @@ -916,6 +1195,25 @@ void HBoundsCheck::InferRepresentation(HInferRepresentationPhase* h_infer) { } +bool HBoundsCheckBaseIndexInformation::IsRelationTrueInternal( + NumericRelation relation, + HValue* related_value, + int offset, + int scale) { + if (related_value == bounds_check()->length()) { + return NumericRelation::Lt().CompoundImplies( + relation, + bounds_check()->offset(), bounds_check()->scale(), offset, scale); + } else if (related_value == block()->graph()->GetConstant0()) { + return NumericRelation::Ge().CompoundImplies( + relation, + bounds_check()->offset(), bounds_check()->scale(), offset, scale); + } else { + return false; + } +} + + void HBoundsCheckBaseIndexInformation::PrintDataTo(StringStream* stream) { stream->Add("base: "); base_index()->PrintNameTo(stream); @@ -1155,29 +1453,6 @@ void HLoadFieldByIndex::PrintDataTo(StringStream* stream) { } -static bool MatchLeftIsOnes(HValue* l, HValue* r, HValue** negated) { - if (!l->EqualsInteger32Constant(~0)) return false; - *negated = r; - return true; -} - - -static bool MatchNegationViaXor(HValue* instr, HValue** negated) { - if (!instr->IsBitwise()) return false; - HBitwise* b = HBitwise::cast(instr); - return (b->op() == Token::BIT_XOR) && - (MatchLeftIsOnes(b->left(), b->right(), negated) || - MatchLeftIsOnes(b->right(), b->left(), negated)); -} - - -static bool MatchDoubleNegation(HValue* instr, HValue** arg) { - HValue* negated; - return MatchNegationViaXor(instr, &negated) && - MatchNegationViaXor(negated, arg); -} - - HValue* HBitwise::Canonicalize() { if (!representation().IsSmiOrInteger32()) return this; // If x is an int32, then x & -1 == x, x | 0 == x and x ^ 0 == x. @@ -1190,10 +1465,18 @@ HValue* HBitwise::Canonicalize() { !left()->CheckFlag(kUint32)) { return left(); } - // Optimize double negation, a common pattern used for ToInt32(x). - HValue* arg; - if (MatchDoubleNegation(this, &arg) && !arg->CheckFlag(kUint32)) { - return arg; + return this; +} + + +HValue* HBitNot::Canonicalize() { + // Optimize ~~x, a common pattern used for ToInt32(x). + if (value()->IsBitNot()) { + HValue* result = HBitNot::cast(value())->value(); + ASSERT(result->representation().IsInteger32()); + if (!result->CheckFlag(kUint32)) { + return result; + } } return this; } @@ -1285,16 +1568,16 @@ static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* dividend) { HValue* HUnaryMathOperation::Canonicalize() { - if (op() == kMathRound || op() == kMathFloor) { + if (op() == kMathRound) { HValue* val = value(); if (val->IsChange()) val = HChange::cast(val)->value(); - // If the input is smi or integer32 then we replace the instruction with its - // input. + // If the input is integer32 then we replace the round instruction + // with its input. if (val->representation().IsSmiOrInteger32()) { if (!val->representation().Equals(representation())) { HChange* result = new(block()->zone()) HChange( - val, representation(), false, false); + val, representation(), false, false, false); result->InsertBefore(this); return result; } @@ -1305,6 +1588,19 @@ HValue* HUnaryMathOperation::Canonicalize() { if (op() == kMathFloor) { HValue* val = value(); if (val->IsChange()) val = HChange::cast(val)->value(); + + // If the input is integer32 then we replace the floor instruction + // with its input. + if (val->representation().IsSmiOrInteger32()) { + if (!val->representation().Equals(representation())) { + HChange* result = new(block()->zone()) HChange( + val, representation(), false, false, false); + result->InsertBefore(this); + return result; + } + return val; + } + if (val->IsDiv() && (val->UseCount() == 1)) { HDiv* hdiv = HDiv::cast(val); HValue* left = hdiv->left(); @@ -1314,7 +1610,7 @@ HValue* HUnaryMathOperation::Canonicalize() { if (new_left == NULL && hdiv->observed_input_representation(1).IsSmiOrInteger32()) { new_left = new(block()->zone()) HChange( - left, Representation::Integer32(), false, false); + left, Representation::Integer32(), false, false, false); HChange::cast(new_left)->InsertBefore(this); } HValue* new_right = @@ -1325,7 +1621,7 @@ HValue* HUnaryMathOperation::Canonicalize() { #endif hdiv->observed_input_representation(2).IsSmiOrInteger32()) { new_right = new(block()->zone()) HChange( - right, Representation::Integer32(), false, false); + right, Representation::Integer32(), false, false, false); HChange::cast(new_right)->InsertBefore(this); } @@ -1416,10 +1712,10 @@ void HCheckMaps::HandleSideEffectDominator(GVNFlag side_effect, // for which the map is known. if (HasNoUses() && dominator->IsStoreNamedField()) { HStoreNamedField* store = HStoreNamedField::cast(dominator); - if (!store->has_transition() || store->object() != value()) return; - HConstant* transition = HConstant::cast(store->transition()); + UniqueValueId map_unique_id = store->transition_unique_id(); + if (!map_unique_id.IsInitialized() || store->object() != value()) return; for (int i = 0; i < map_set()->length(); i++) { - if (transition->UniqueValueIdsMatch(map_unique_ids_.at(i))) { + if (map_unique_id == map_unique_ids_.at(i)) { DeleteAndReplaceWith(NULL); return; } @@ -1470,6 +1766,13 @@ void HCheckInstanceType::PrintDataTo(StringStream* stream) { } +void HCheckPrototypeMaps::PrintDataTo(StringStream* stream) { + stream->Add("[receiver_prototype=%p,holder=%p]%s", + *prototypes_.first(), *prototypes_.last(), + CanOmitPrototypeChecks() ? " (omitted)" : ""); +} + + void HCallStub::PrintDataTo(StringStream* stream) { stream->Add("%s ", CodeStub::MajorName(major_key_, false)); @@ -1672,6 +1975,60 @@ Range* HMod::InferRange(Zone* zone) { } +void HPhi::AddInformativeDefinitions() { + if (OperandCount() == 2) { + // If one of the operands is an OSR block give up (this cannot be an + // induction variable). + if (OperandAt(0)->block()->is_osr_entry() || + OperandAt(1)->block()->is_osr_entry()) return; + + for (int operand_index = 0; operand_index < 2; operand_index++) { + int other_operand_index = (operand_index + 1) % 2; + + static NumericRelation relations[] = { + NumericRelation::Ge(), + NumericRelation::Le() + }; + + // Check if this phi is an induction variable. If, e.g., we know that + // its first input is greater than the phi itself, then that must be + // the back edge, and the phi is always greater than its second input. + for (int relation_index = 0; relation_index < 2; relation_index++) { + if (OperandAt(operand_index)->IsRelationTrue(relations[relation_index], + this)) { + HInductionVariableAnnotation::AddToGraph(this, + relations[relation_index], + other_operand_index); + } + } + } + } +} + + +bool HPhi::IsRelationTrueInternal(NumericRelation relation, + HValue* other, + int offset, + int scale) { + if (CheckFlag(kNumericConstraintEvaluationInProgress)) return false; + + SetFlag(kNumericConstraintEvaluationInProgress); + bool result = true; + for (int i = 0; i < OperandCount(); i++) { + // Skip OSR entry blocks + if (OperandAt(i)->block()->is_osr_entry()) continue; + + if (!OperandAt(i)->IsRelationTrue(relation, other, offset, scale)) { + result = false; + break; + } + } + ClearFlag(kNumericConstraintEvaluationInProgress); + + return result; +} + + InductionVariableData* InductionVariableData::ExaminePhi(HPhi* phi) { if (phi->block()->loop_information() == NULL) return NULL; if (phi->OperandCount() != 2) return NULL; @@ -2423,14 +2780,6 @@ HConstant::HConstant(ExternalReference reference) } -static void PrepareConstant(Handle<Object> object) { - if (!object->IsJSObject()) return; - Handle<JSObject> js_object = Handle<JSObject>::cast(object); - if (!js_object->map()->is_deprecated()) return; - JSObject::TryMigrateInstance(js_object); -} - - void HConstant::Initialize(Representation r) { if (r.IsNone()) { if (has_smi_value_ && kSmiValueSize == 31) { @@ -2442,7 +2791,6 @@ void HConstant::Initialize(Representation r) { } else if (has_external_reference_value_) { r = Representation::External(); } else { - PrepareConstant(handle_); r = Representation::Tagged(); } } @@ -2767,6 +3115,16 @@ void HStringCompareAndBranch::PrintDataTo(StringStream* stream) { } +void HCompareNumericAndBranch::AddInformativeDefinitions() { + NumericRelation r = NumericRelation::FromToken(token()); + if (r.IsNone()) return; + + HNumericConstraint::AddToGraph(left(), r, right(), SuccessorAt(0)->first()); + HNumericConstraint::AddToGraph( + left(), r.Negated(), right(), SuccessorAt(1)->first()); +} + + void HCompareNumericAndBranch::PrintDataTo(StringStream* stream) { stream->Add(Token::Name(token())); stream->Add(" "); @@ -2785,18 +3143,6 @@ void HCompareObjectEqAndBranch::PrintDataTo(StringStream* stream) { } -void HCompareHoleAndBranch::PrintDataTo(StringStream* stream) { - object()->PrintNameTo(stream); - HControlInstruction::PrintDataTo(stream); -} - - -void HCompareHoleAndBranch::InferRepresentation( - HInferRepresentationPhase* h_infer) { - ChangeRepresentation(object()->representation()); -} - - void HGoto::PrintDataTo(StringStream* stream) { stream->Add("B%d", SuccessorAt(0)->block_id()); } @@ -2856,6 +3202,119 @@ void HLoadNamedField::PrintDataTo(StringStream* stream) { } +// Returns true if an instance of this map can never find a property with this +// name in its prototype chain. This means all prototypes up to the top are +// fast and don't have the name in them. It would be good if we could optimize +// polymorphic loads where the property is sometimes found in the prototype +// chain. +static bool PrototypeChainCanNeverResolve( + Handle<Map> map, Handle<String> name) { + Isolate* isolate = map->GetIsolate(); + Object* current = map->prototype(); + while (current != isolate->heap()->null_value()) { + if (current->IsJSGlobalProxy() || + current->IsGlobalObject() || + !current->IsJSObject() || + JSObject::cast(current)->map()->has_named_interceptor() || + JSObject::cast(current)->IsAccessCheckNeeded() || + !JSObject::cast(current)->HasFastProperties()) { + return false; + } + + LookupResult lookup(isolate); + Map* map = JSObject::cast(current)->map(); + map->LookupDescriptor(NULL, *name, &lookup); + if (lookup.IsFound()) return false; + if (!lookup.IsCacheable()) return false; + current = JSObject::cast(current)->GetPrototype(); + } + return true; +} + + +HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context, + HValue* object, + SmallMapList* types, + Handle<String> name, + Zone* zone) + : types_(Min(types->length(), kMaxLoadPolymorphism), zone), + name_(name), + types_unique_ids_(0, zone), + name_unique_id_(), + need_generic_(false) { + SetOperandAt(0, context); + SetOperandAt(1, object); + set_representation(Representation::Tagged()); + SetGVNFlag(kDependsOnMaps); + SmallMapList negative_lookups; + for (int i = 0; + i < types->length() && types_.length() < kMaxLoadPolymorphism; + ++i) { + Handle<Map> map = types->at(i); + // Deprecated maps are updated to the current map in the type oracle. + ASSERT(!map->is_deprecated()); + LookupResult lookup(map->GetIsolate()); + map->LookupDescriptor(NULL, *name, &lookup); + if (lookup.IsFound()) { + switch (lookup.type()) { + case FIELD: { + int index = lookup.GetLocalFieldIndexFromMap(*map); + if (index < 0) { + SetGVNFlag(kDependsOnInobjectFields); + } else { + SetGVNFlag(kDependsOnBackingStoreFields); + } + if (FLAG_track_double_fields && + lookup.representation().IsDouble()) { + // Since the value needs to be boxed, use a generic handler for + // loading doubles. + continue; + } + types_.Add(types->at(i), zone); + break; + } + case CONSTANT: + types_.Add(types->at(i), zone); + break; + case CALLBACKS: + break; + case TRANSITION: + case INTERCEPTOR: + case NONEXISTENT: + case NORMAL: + case HANDLER: + UNREACHABLE(); + break; + } + } else if (lookup.IsCacheable() && + // For dicts the lookup on the map will fail, but the object may + // contain the property so we cannot generate a negative lookup + // (which would just be a map check and return undefined). + !map->is_dictionary_map() && + !map->has_named_interceptor() && + PrototypeChainCanNeverResolve(map, name)) { + negative_lookups.Add(types->at(i), zone); + } + } + + bool need_generic = + (types->length() != negative_lookups.length() + types_.length()); + if (!need_generic && FLAG_deoptimize_uncommon_cases) { + SetFlag(kUseGVN); + for (int i = 0; i < negative_lookups.length(); i++) { + types_.Add(negative_lookups.at(i), zone); + } + } else { + // We don't have an easy way to handle both a call (to the generic stub) and + // a deopt in the same hydrogen instruction, so in this case we don't add + // the negative lookups which can deopt - just let the generic stub handle + // them. + SetAllSideEffects(); + need_generic_ = true; + } +} + + HCheckMaps* HCheckMaps::New(Zone* zone, HValue* context, HValue* value, @@ -2863,7 +3322,7 @@ HCheckMaps* HCheckMaps::New(Zone* zone, CompilationInfo* info, HValue* typecheck) { HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck); - check_map->Add(map, zone); + check_map->map_set_.Add(map, zone); if (map->CanOmitMapChecks() && value->IsConstant() && HConstant::cast(value)->InstanceOf(map)) { @@ -2883,6 +3342,46 @@ void HCheckMaps::FinalizeUniqueValueId() { } +void HLoadNamedFieldPolymorphic::FinalizeUniqueValueId() { + if (!types_unique_ids_.is_empty()) return; + Zone* zone = block()->zone(); + types_unique_ids_.Initialize(types_.length(), zone); + for (int i = 0; i < types_.length(); i++) { + types_unique_ids_.Add(UniqueValueId(types_.at(i)), zone); + } + name_unique_id_ = UniqueValueId(name_); +} + + +bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) { + ASSERT_EQ(types_.length(), types_unique_ids_.length()); + HLoadNamedFieldPolymorphic* other = HLoadNamedFieldPolymorphic::cast(value); + if (name_unique_id_ != other->name_unique_id_) return false; + if (types_unique_ids_.length() != other->types_unique_ids_.length()) { + return false; + } + if (need_generic_ != other->need_generic_) return false; + for (int i = 0; i < types_unique_ids_.length(); i++) { + bool found = false; + for (int j = 0; j < types_unique_ids_.length(); j++) { + if (types_unique_ids_.at(j) == other->types_unique_ids_.at(i)) { + found = true; + break; + } + } + if (!found) return false; + } + return true; +} + + +void HLoadNamedFieldPolymorphic::PrintDataTo(StringStream* stream) { + object()->PrintNameTo(stream); + stream->Add("."); + stream->Add(*String::cast(*name())->ToCString()); +} + + void HLoadNamedGeneric::PrintDataTo(StringStream* stream) { object()->PrintNameTo(stream); stream->Add("."); @@ -2955,8 +3454,18 @@ bool HLoadKeyed::UsesMustHandleHole() const { bool HLoadKeyed::AllUsesCanTreatHoleAsNaN() const { - return IsFastDoubleElementsKind(elements_kind()) && - CheckUsesForFlag(HValue::kAllowUndefinedAsNaN); + if (!IsFastDoubleElementsKind(elements_kind())) { + return false; + } + + for (HUseIterator it(uses()); !it.Done(); it.Advance()) { + HValue* use = it.value(); + if (!use->CheckFlag(HValue::kAllowUndefinedAsNaN)) { + return false; + } + } + + return true; } @@ -3038,8 +3547,8 @@ void HStoreNamedField::PrintDataTo(StringStream* stream) { if (NeedsWriteBarrier()) { stream->Add(" (write-barrier)"); } - if (has_transition()) { - stream->Add(" (transition map %p)", *transition_map()); + if (!transition().is_null()) { + stream->Add(" (transition map %p)", *transition()); } } @@ -3175,6 +3684,8 @@ Representation HUnaryMathOperation::RepresentationFromInputs() { Representation input_rep = value()->representation(); if (!input_rep.IsTagged()) { rep = rep.generalize(input_rep); + } else if (flexible_int()) { + rep = Representation::Integer32(); } return rep; } @@ -3731,10 +4242,10 @@ void HPhi::SimplifyConstantInputs() { DoubleToInt32(operand->DoubleValue())); integer_input->InsertAfter(operand); SetOperandAt(i, integer_input); - } else if (operand->HasBooleanValue()) { - SetOperandAt(i, operand->BooleanValue() ? graph->GetConstant1() - : graph->GetConstant0()); - } else if (operand->ImmortalImmovable()) { + } else if (operand == graph->GetConstantTrue()) { + SetOperandAt(i, graph->GetConstant1()); + } else { + // This catches |false|, |undefined|, strings and objects. SetOperandAt(i, graph->GetConstant0()); } } diff --git a/chromium/v8/src/hydrogen-instructions.h b/chromium/v8/src/hydrogen-instructions.h index 41f9d0d5ccd..78e9a6b192a 100644 --- a/chromium/v8/src/hydrogen-instructions.h +++ b/chromium/v8/src/hydrogen-instructions.h @@ -72,6 +72,7 @@ class LChunkBuilder; V(ArgumentsLength) \ V(ArgumentsObject) \ V(Bitwise) \ + V(BitNot) \ V(BlockEntry) \ V(BoundsCheck) \ V(BoundsCheckBaseIndexInformation) \ @@ -86,18 +87,17 @@ class LChunkBuilder; V(CallNewArray) \ V(CallRuntime) \ V(CallStub) \ - V(CapturedObject) \ V(Change) \ V(CheckFunction) \ V(CheckHeapObject) \ V(CheckInstanceType) \ V(CheckMaps) \ V(CheckMapValue) \ + V(CheckPrototypeMaps) \ V(CheckSmi) \ V(ClampToUint8) \ V(ClassOfTestAndBranch) \ V(CompareNumericAndBranch) \ - V(CompareHoleAndBranch) \ V(CompareGeneric) \ V(CompareObjectEqAndBranch) \ V(CompareMap) \ @@ -122,6 +122,7 @@ class LChunkBuilder; V(Goto) \ V(HasCachedArrayIndexAndBranch) \ V(HasInstanceTypeAndBranch) \ + V(InductionVariableAnnotation) \ V(InnerAllocatedObject) \ V(InstanceOf) \ V(InstanceOfKnownGlobal) \ @@ -143,12 +144,14 @@ class LChunkBuilder; V(LoadKeyed) \ V(LoadKeyedGeneric) \ V(LoadNamedField) \ + V(LoadNamedFieldPolymorphic) \ V(LoadNamedGeneric) \ V(MapEnumLength) \ V(MathFloorOfDiv) \ V(MathMinMax) \ V(Mod) \ V(Mul) \ + V(NumericConstraint) \ V(OsrEntry) \ V(OuterContext) \ V(Parameter) \ @@ -539,6 +542,158 @@ enum GVNFlag { }; +class NumericRelation { + public: + enum Kind { NONE, EQ, GT, GE, LT, LE, NE }; + static const char* MnemonicFromKind(Kind kind) { + switch (kind) { + case NONE: return "NONE"; + case EQ: return "EQ"; + case GT: return "GT"; + case GE: return "GE"; + case LT: return "LT"; + case LE: return "LE"; + case NE: return "NE"; + } + UNREACHABLE(); + return NULL; + } + const char* Mnemonic() const { return MnemonicFromKind(kind_); } + + static NumericRelation None() { return NumericRelation(NONE); } + static NumericRelation Eq() { return NumericRelation(EQ); } + static NumericRelation Gt() { return NumericRelation(GT); } + static NumericRelation Ge() { return NumericRelation(GE); } + static NumericRelation Lt() { return NumericRelation(LT); } + static NumericRelation Le() { return NumericRelation(LE); } + static NumericRelation Ne() { return NumericRelation(NE); } + + bool IsNone() { return kind_ == NONE; } + + static NumericRelation FromToken(Token::Value token) { + switch (token) { + case Token::EQ: return Eq(); + case Token::EQ_STRICT: return Eq(); + case Token::LT: return Lt(); + case Token::GT: return Gt(); + case Token::LTE: return Le(); + case Token::GTE: return Ge(); + case Token::NE: return Ne(); + case Token::NE_STRICT: return Ne(); + default: return None(); + } + } + + // The semantics of "Reversed" is that if "x rel y" is true then also + // "y rel.Reversed() x" is true, and that rel.Reversed().Reversed() == rel. + NumericRelation Reversed() { + switch (kind_) { + case NONE: return None(); + case EQ: return Eq(); + case GT: return Lt(); + case GE: return Le(); + case LT: return Gt(); + case LE: return Ge(); + case NE: return Ne(); + } + UNREACHABLE(); + return None(); + } + + // The semantics of "Negated" is that if "x rel y" is true then also + // "!(x rel.Negated() y)" is true. + NumericRelation Negated() { + switch (kind_) { + case NONE: return None(); + case EQ: return Ne(); + case GT: return Le(); + case GE: return Lt(); + case LT: return Ge(); + case LE: return Gt(); + case NE: return Eq(); + } + UNREACHABLE(); + return None(); + } + + // The semantics of "Implies" is that if "x rel y" is true + // then also "x other_relation y" is true. + bool Implies(NumericRelation other_relation) { + switch (kind_) { + case NONE: return false; + case EQ: return (other_relation.kind_ == EQ) + || (other_relation.kind_ == GE) + || (other_relation.kind_ == LE); + case GT: return (other_relation.kind_ == GT) + || (other_relation.kind_ == GE) + || (other_relation.kind_ == NE); + case LT: return (other_relation.kind_ == LT) + || (other_relation.kind_ == LE) + || (other_relation.kind_ == NE); + case GE: return (other_relation.kind_ == GE); + case LE: return (other_relation.kind_ == LE); + case NE: return (other_relation.kind_ == NE); + } + UNREACHABLE(); + return false; + } + + // The semantics of "IsExtendable" is that if + // "rel.IsExtendable(direction)" is true then + // "x rel y" implies "(x + direction) rel y" . + bool IsExtendable(int direction) { + switch (kind_) { + case NONE: return false; + case EQ: return false; + case GT: return (direction >= 0); + case GE: return (direction >= 0); + case LT: return (direction <= 0); + case LE: return (direction <= 0); + case NE: return false; + } + UNREACHABLE(); + return false; + } + + // CompoundImplies returns true when + // "((x + my_offset) >> my_scale) rel y" implies + // "((x + other_offset) >> other_scale) other_relation y". + bool CompoundImplies(NumericRelation other_relation, + int my_offset, + int my_scale, + int other_offset = 0, + int other_scale = 0) { + return Implies(other_relation) && ComponentsImply( + my_offset, my_scale, other_offset, other_scale); + } + + private: + // ComponentsImply returns true when + // "((x + my_offset) >> my_scale) rel y" implies + // "((x + other_offset) >> other_scale) rel y". + bool ComponentsImply(int my_offset, + int my_scale, + int other_offset, + int other_scale) { + switch (kind_) { + case NONE: break; // Fall through to UNREACHABLE(). + case EQ: + case NE: return my_offset == other_offset && my_scale == other_scale; + case GT: + case GE: return my_offset <= other_offset && my_scale >= other_scale; + case LT: + case LE: return my_offset >= other_offset && my_scale <= other_scale; + } + UNREACHABLE(); + return false; + } + + explicit NumericRelation(Kind kind) : kind_(kind) {} + + Kind kind_; +}; + + class DecompositionResult BASE_EMBEDDED { public: DecompositionResult() : base_(NULL), offset_(0), scale_(0) {} @@ -584,6 +739,46 @@ class DecompositionResult BASE_EMBEDDED { }; +class RangeEvaluationContext BASE_EMBEDDED { + public: + RangeEvaluationContext(HValue* value, HValue* upper); + + HValue* lower_bound() { return lower_bound_; } + HValue* lower_bound_guarantee() { return lower_bound_guarantee_; } + HValue* candidate() { return candidate_; } + HValue* upper_bound() { return upper_bound_; } + HValue* upper_bound_guarantee() { return upper_bound_guarantee_; } + int offset() { return offset_; } + int scale() { return scale_; } + + bool is_range_satisfied() { + return lower_bound_guarantee() != NULL && upper_bound_guarantee() != NULL; + } + + void set_lower_bound_guarantee(HValue* guarantee) { + lower_bound_guarantee_ = ConvertGuarantee(guarantee); + } + void set_upper_bound_guarantee(HValue* guarantee) { + upper_bound_guarantee_ = ConvertGuarantee(guarantee); + } + + void swap_candidate(DecompositionResult* other_candicate) { + other_candicate->SwapValues(&candidate_, &offset_, &scale_); + } + + private: + HValue* ConvertGuarantee(HValue* guarantee); + + HValue* lower_bound_; + HValue* lower_bound_guarantee_; + HValue* candidate_; + HValue* upper_bound_; + HValue* upper_bound_guarantee_; + int offset_; + int scale_; +}; + + typedef EnumSet<GVNFlag> GVNFlagSet; @@ -621,6 +816,12 @@ class HValue: public ZoneObject { // HGraph::ComputeSafeUint32Operations is responsible for setting this // flag. kUint32, + // If a phi is involved in the evaluation of a numeric constraint the + // recursion can cause an endless cycle: we use this flag to exit the loop. + kNumericConstraintEvaluationInProgress, + // This flag is set to true after the SetupInformativeDefinitions() pass + // has processed this instruction. + kIDefsProcessingDone, kHasNoObservableSideEffects, // Indicates the instruction is live during dead code elimination. kIsLive, @@ -758,8 +959,8 @@ class HValue: public ZoneObject { return RedefinedOperandIndex() != kNoRedefinedOperand; } HValue* RedefinedOperand() { - int index = RedefinedOperandIndex(); - return index == kNoRedefinedOperand ? NULL : OperandAt(index); + return IsInformativeDefinition() ? OperandAt(RedefinedOperandIndex()) + : NULL; } // A purely informative definition is an idef that will not emit code and @@ -770,8 +971,17 @@ class HValue: public ZoneObject { // This method must always return the original HValue SSA definition // (regardless of any iDef of this value). HValue* ActualValue() { - int index = RedefinedOperandIndex(); - return index == kNoRedefinedOperand ? this : OperandAt(index); + return IsInformativeDefinition() ? RedefinedOperand()->ActualValue() + : this; + } + + virtual void AddInformativeDefinitions() {} + + void UpdateRedefinedUsesWhileSettingUpInformativeDefinitions() { + UpdateRedefinedUsesInner<TestDominanceUsingProcessedFlag>(); + } + void UpdateRedefinedUses() { + UpdateRedefinedUsesInner<Dominates>(); } bool IsInteger32Constant(); @@ -802,10 +1012,10 @@ class HValue: public ZoneObject { bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; } // Returns true if the flag specified is set for all uses, false otherwise. - bool CheckUsesForFlag(Flag f) const; + bool CheckUsesForFlag(Flag f); // Returns true if the flag specified is set for all uses, and this set // of uses is non-empty. - bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const; + bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f); GVNFlagSet gvn_flags() const { return gvn_flags_; } void SetGVNFlag(GVNFlag f) { gvn_flags_.Add(f); } @@ -922,6 +1132,12 @@ class HValue: public ZoneObject { virtual void Verify() = 0; #endif + bool IsRelationTrue(NumericRelation relation, + HValue* other, + int offset = 0, + int scale = 0); + + bool TryGuaranteeRange(HValue* upper_bound); virtual bool TryDecompose(DecompositionResult* decomposition) { if (RedefinedOperand() != NULL) { return RedefinedOperand()->TryDecompose(decomposition); @@ -943,6 +1159,17 @@ class HValue: public ZoneObject { } protected: + void TryGuaranteeRangeRecursive(RangeEvaluationContext* context); + + enum RangeGuaranteeDirection { + DIRECTION_NONE = 0, + DIRECTION_UPPER = 1, + DIRECTION_LOWER = 2, + DIRECTION_BOTH = DIRECTION_UPPER | DIRECTION_LOWER + }; + virtual void SetResponsibilityForRange(RangeGuaranteeDirection direction) {} + virtual void TryGuaranteeRangeChanging(RangeEvaluationContext* context) {} + // This function must be overridden for instructions with flag kUseGVN, to // compare the non-Operand parts of the instruction. virtual bool DataEquals(HValue* other) { @@ -976,6 +1203,47 @@ class HValue: public ZoneObject { representation_ = r; } + // Signature of a function testing if a HValue properly dominates another. + typedef bool (*DominanceTest)(HValue*, HValue*); + + // Simple implementation of DominanceTest implemented walking the chain + // of Hinstructions (used in UpdateRedefinedUsesInner). + static bool Dominates(HValue* dominator, HValue* dominated); + + // A fast implementation of DominanceTest that works only for the + // "current" instruction in the SetupInformativeDefinitions() phase. + // During that phase we use a flag to mark processed instructions, and by + // checking the flag we can quickly test if an instruction comes before or + // after the "current" one. + static bool TestDominanceUsingProcessedFlag(HValue* dominator, + HValue* dominated); + + // If we are redefining an operand, update all its dominated uses (the + // function that checks if a use is dominated is the template argument). + template<DominanceTest TestDominance> + void UpdateRedefinedUsesInner() { + HValue* input = RedefinedOperand(); + if (input != NULL) { + for (HUseIterator uses = input->uses(); !uses.Done(); uses.Advance()) { + HValue* use = uses.value(); + if (TestDominance(this, use)) { + use->SetOperandAt(uses.index(), this); + } + } + } + } + + // Informative definitions can override this method to state any numeric + // relation they provide on the redefined value. + // Returns true if it is guaranteed that: + // ((this + offset) >> scale) relation other + virtual bool IsRelationTrueInternal(NumericRelation relation, + HValue* other, + int offset = 0, + int scale = 0) { + return false; + } + static GVNFlagSet AllDependsOnFlagSet() { GVNFlagSet result; // Create changes mask. @@ -1246,25 +1514,67 @@ class HDummyUse: public HTemplateInstruction<1> { }; +class HNumericConstraint : public HTemplateInstruction<2> { + public: + static HNumericConstraint* AddToGraph(HValue* constrained_value, + NumericRelation relation, + HValue* related_value, + HInstruction* insertion_point = NULL); + + HValue* constrained_value() { return OperandAt(0); } + HValue* related_value() { return OperandAt(1); } + NumericRelation relation() { return relation_; } + + virtual int RedefinedOperandIndex() { return 0; } + virtual bool IsPurelyInformativeDefinition() { return true; } + + virtual Representation RequiredInputRepresentation(int index) { + return representation(); + } + + virtual void PrintDataTo(StringStream* stream); + + virtual bool IsRelationTrueInternal(NumericRelation other_relation, + HValue* other_related_value, + int offset = 0, + int scale = 0) { + if (related_value() == other_related_value) { + return relation().CompoundImplies(other_relation, offset, scale); + } else { + return false; + } + } + + DECLARE_CONCRETE_INSTRUCTION(NumericConstraint) + + private: + HNumericConstraint(HValue* constrained_value, + NumericRelation relation, + HValue* related_value) + : relation_(relation) { + SetOperandAt(0, constrained_value); + SetOperandAt(1, related_value); + } + + NumericRelation relation_; +}; + + class HDeoptimize: public HTemplateInstruction<0> { public: - DECLARE_INSTRUCTION_FACTORY_P2(HDeoptimize, const char*, - Deoptimizer::BailoutType); + DECLARE_INSTRUCTION_FACTORY_P1(HDeoptimize, Deoptimizer::BailoutType); virtual Representation RequiredInputRepresentation(int index) { return Representation::None(); } - const char* reason() const { return reason_; } Deoptimizer::BailoutType type() { return type_; } DECLARE_CONCRETE_INSTRUCTION(Deoptimize) private: - explicit HDeoptimize(const char* reason, Deoptimizer::BailoutType type) - : reason_(reason), type_(type) {} + explicit HDeoptimize(Deoptimizer::BailoutType type) : type_(type) {} - const char* reason_; Deoptimizer::BailoutType type_; }; @@ -1522,13 +1832,15 @@ class HChange: public HUnaryOperation { HChange(HValue* value, Representation to, bool is_truncating_to_smi, - bool is_truncating_to_int32) + bool is_truncating_to_int32, + bool allow_undefined_as_nan) : HUnaryOperation(value) { ASSERT(!value->representation().IsNone()); ASSERT(!to.IsNone()); ASSERT(!value->representation().Equals(to)); set_representation(to); SetFlag(kUseGVN); + if (allow_undefined_as_nan) SetFlag(kAllowUndefinedAsNaN); if (is_truncating_to_smi) SetFlag(kTruncatingToSmi); if (is_truncating_to_int32) SetFlag(kTruncatingToInt32); if (value->representation().IsSmi() || value->type().IsSmi()) { @@ -1539,16 +1851,15 @@ class HChange: public HUnaryOperation { } } - bool can_convert_undefined_to_nan() { - return CheckUsesForFlag(kAllowUndefinedAsNaN); - } - virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); virtual HType CalculateInferredType(); virtual HValue* Canonicalize(); Representation from() const { return value()->representation(); } Representation to() const { return representation(); } + bool allow_undefined_as_nan() const { + return CheckFlag(kAllowUndefinedAsNaN); + } bool deoptimize_on_minus_zero() const { return CheckFlag(kBailoutOnMinusZero); } @@ -2395,6 +2706,37 @@ class HElementsKind: public HUnaryOperation { }; +class HBitNot: public HUnaryOperation { + public: + DECLARE_INSTRUCTION_FACTORY_P1(HBitNot, HValue*); + + virtual Representation RequiredInputRepresentation(int index) { + return Representation::Integer32(); + } + virtual Representation observed_input_representation(int index) { + return Representation::Integer32(); + } + + virtual HValue* Canonicalize(); + + DECLARE_CONCRETE_INSTRUCTION(BitNot) + + protected: + virtual bool DataEquals(HValue* other) { return true; } + + private: + explicit HBitNot(HValue* value) + : HUnaryOperation(value, HType::TaggedNumber()) { + set_representation(Representation::Integer32()); + SetFlag(kUseGVN); + SetFlag(kTruncatingToInt32); + SetFlag(kAllowUndefinedAsNaN); + } + + virtual bool IsDeletable() const { return true; } +}; + + class HUnaryMathOperation: public HTemplateInstruction<2> { public: static HInstruction* New(Zone* zone, @@ -2433,6 +2775,21 @@ class HUnaryMathOperation: public HTemplateInstruction<2> { } } + virtual void UpdateRepresentation(Representation new_rep, + HInferRepresentationPhase* h_infer, + const char* reason) { + if (flexible_int() && !new_rep.IsSmi()) { + new_rep = Representation::Integer32(); + } + HValue::UpdateRepresentation(new_rep, h_infer, reason); + } + + virtual void RepresentationChanged(Representation new_rep) { + if (flexible_int() && new_rep.IsInteger32()) { + ClearFlag(kFlexibleRepresentation); + } + } + virtual Range* InferRange(Zone* zone); virtual HValue* Canonicalize(); @@ -2450,6 +2807,10 @@ class HUnaryMathOperation: public HTemplateInstruction<2> { } private: + bool flexible_int() { + return op_ == kMathFloor || op_ == kMathRound; + } + HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op) : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) { SetOperandAt(0, context); @@ -2457,7 +2818,8 @@ class HUnaryMathOperation: public HTemplateInstruction<2> { switch (op) { case kMathFloor: case kMathRound: - set_representation(Representation::Integer32()); + set_representation(Representation::Smi()); + SetFlag(kFlexibleRepresentation); break; case kMathAbs: // Not setting representation here: it is None intentionally. @@ -2534,7 +2896,7 @@ class HCheckMaps: public HTemplateInstruction<2> { HValue *typecheck = NULL) { HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck); for (int i = 0; i < maps->length(); i++) { - check_map->Add(maps->at(i), zone); + check_map->map_set_.Add(maps->at(i), zone); } check_map->map_set_.Sort(); return check_map; @@ -2553,10 +2915,6 @@ class HCheckMaps: public HTemplateInstruction<2> { HValue* value() { return OperandAt(0); } SmallMapList* map_set() { return &map_set_; } - bool has_migration_target() { - return has_migration_target_; - } - virtual void FinalizeUniqueValueId(); DECLARE_CONCRETE_INSTRUCTION(CheckMaps) @@ -2578,18 +2936,10 @@ class HCheckMaps: public HTemplateInstruction<2> { } private: - void Add(Handle<Map> map, Zone* zone) { - map_set_.Add(map, zone); - if (!has_migration_target_ && map->is_migration_target()) { - has_migration_target_ = true; - SetGVNFlag(kChangesNewSpacePromotion); - } - } - // Clients should use one of the static New* methods above. HCheckMaps(HValue* value, Zone *zone, HValue* typecheck) : HTemplateInstruction<2>(value->type()), - omit_(false), has_migration_target_(false), map_unique_ids_(0, zone) { + omit_(false), map_unique_ids_(0, zone) { SetOperandAt(0, value); // Use the object value for the dependency if NULL is passed. // TODO(titzer): do GVN flags already express this dependency? @@ -2611,7 +2961,6 @@ class HCheckMaps: public HTemplateInstruction<2> { } bool omit_; - bool has_migration_target_; SmallMapList map_set_; ZoneList<UniqueValueId> map_unique_ids_; }; @@ -2770,7 +3119,6 @@ class HCheckHeapObject: public HUnaryOperation { public: DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*); - virtual bool HasEscapingOperandAt(int index) { return false; } virtual Representation RequiredInputRepresentation(int index) { return Representation::Tagged(); } @@ -2797,6 +3145,87 @@ class HCheckHeapObject: public HUnaryOperation { }; +class HCheckPrototypeMaps: public HTemplateInstruction<0> { + public: + static HCheckPrototypeMaps* New(Zone* zone, + HValue* context, + Handle<JSObject> prototype, + Handle<JSObject> holder, + CompilationInfo* info) { + return new(zone) HCheckPrototypeMaps(prototype, holder, zone, info); + } + + ZoneList<Handle<JSObject> >* prototypes() { return &prototypes_; } + + ZoneList<Handle<Map> >* maps() { return &maps_; } + + DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps) + + virtual Representation RequiredInputRepresentation(int index) { + return Representation::None(); + } + + virtual void PrintDataTo(StringStream* stream); + + virtual intptr_t Hashcode() { + return first_prototype_unique_id_.Hashcode() * 17 + + last_prototype_unique_id_.Hashcode(); + } + + virtual void FinalizeUniqueValueId() { + first_prototype_unique_id_ = UniqueValueId(prototypes_.first()); + last_prototype_unique_id_ = UniqueValueId(prototypes_.last()); + } + + bool CanOmitPrototypeChecks() { return can_omit_prototype_maps_; } + + protected: + virtual bool DataEquals(HValue* other) { + HCheckPrototypeMaps* b = HCheckPrototypeMaps::cast(other); + return first_prototype_unique_id_ == b->first_prototype_unique_id_ && + last_prototype_unique_id_ == b->last_prototype_unique_id_; + } + + private: + HCheckPrototypeMaps(Handle<JSObject> prototype, + Handle<JSObject> holder, + Zone* zone, + CompilationInfo* info) + : prototypes_(2, zone), + maps_(2, zone), + first_prototype_unique_id_(), + last_prototype_unique_id_(), + can_omit_prototype_maps_(true) { + SetFlag(kUseGVN); + SetGVNFlag(kDependsOnMaps); + // Keep a list of all objects on the prototype chain up to the holder + // and the expected maps. + while (true) { + prototypes_.Add(prototype, zone); + Handle<Map> map(prototype->map()); + maps_.Add(map, zone); + can_omit_prototype_maps_ &= map->CanOmitPrototypeChecks(); + if (prototype.is_identical_to(holder)) break; + prototype = Handle<JSObject>(JSObject::cast(prototype->GetPrototype())); + } + if (can_omit_prototype_maps_) { + // Mark in-flight compilation as dependent on those maps. + for (int i = 0; i < maps()->length(); i++) { + Handle<Map> map = maps()->at(i); + map->AddDependentCompilationInfo(DependentCode::kPrototypeCheckGroup, + info); + } + } + } + + ZoneList<Handle<JSObject> > prototypes_; + ZoneList<Handle<Map> > maps_; + UniqueValueId first_prototype_unique_id_; + UniqueValueId last_prototype_unique_id_; + bool can_omit_prototype_maps_; +}; + + class InductionVariableData; @@ -3071,6 +3500,8 @@ class HPhi: public HValue { induction_variable_data_ = InductionVariableData::ExaminePhi(this); } + virtual void AddInformativeDefinitions(); + virtual void PrintTo(StringStream* stream); #ifdef DEBUG @@ -3124,6 +3555,11 @@ class HPhi: public HValue { inputs_[index] = value; } + virtual bool IsRelationTrueInternal(NumericRelation relation, + HValue* other, + int offset = 0, + int scale = 0); + private: ZoneList<HValue*> inputs_; int merged_index_; @@ -3138,40 +3574,61 @@ class HPhi: public HValue { }; -// Common base class for HArgumentsObject and HCapturedObject. -class HDematerializedObject: public HTemplateInstruction<0> { +class HInductionVariableAnnotation : public HUnaryOperation { public: - HDematerializedObject(int count, Zone* zone) : values_(count, zone) {} + static HInductionVariableAnnotation* AddToGraph(HPhi* phi, + NumericRelation relation, + int operand_index); - virtual int OperandCount() { return values_.length(); } - virtual HValue* OperandAt(int index) const { return values_[index]; } + NumericRelation relation() { return relation_; } + HValue* induction_base() { return phi_->OperandAt(operand_index_); } - virtual bool HasEscapingOperandAt(int index) { return false; } + virtual int RedefinedOperandIndex() { return 0; } + virtual bool IsPurelyInformativeDefinition() { return true; } virtual Representation RequiredInputRepresentation(int index) { - return Representation::None(); + return representation(); } - protected: - virtual void InternalSetOperandAt(int index, HValue* value) { - values_[index] = value; + virtual void PrintDataTo(StringStream* stream); + + virtual bool IsRelationTrueInternal(NumericRelation other_relation, + HValue* other_related_value, + int offset = 0, + int scale = 0) { + if (induction_base() == other_related_value) { + return relation().CompoundImplies(other_relation, offset, scale); + } else { + return false; + } } - // List of values tracked by this marker. - ZoneList<HValue*> values_; + DECLARE_CONCRETE_INSTRUCTION(InductionVariableAnnotation) private: - virtual bool IsDeletable() const { return true; } + HInductionVariableAnnotation(HPhi* phi, + NumericRelation relation, + int operand_index) + : HUnaryOperation(phi), + phi_(phi), relation_(relation), operand_index_(operand_index) { + } + + // We need to store the phi both here and in the instruction operand because + // the operand can change if a new idef of the phi is added between the phi + // and this instruction (inserting an idef updates every use). + HPhi* phi_; + NumericRelation relation_; + int operand_index_; }; -class HArgumentsObject: public HDematerializedObject { +class HArgumentsObject: public HTemplateInstruction<0> { public: - static HArgumentsObject* New(Zone* zone, HValue* context, int count) { + static HArgumentsObject* New(Zone* zone, + HValue* context, + int count) { return new(zone) HArgumentsObject(count, zone); } - // The values contain a list of all elements in the arguments object - // including the receiver object, which is skipped when materializing. const ZoneList<HValue*>* arguments_values() const { return &values_; } int arguments_count() const { return values_.length(); } @@ -3180,32 +3637,30 @@ class HArgumentsObject: public HDematerializedObject { SetOperandAt(values_.length() - 1, argument); } - DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject) + virtual int OperandCount() { return values_.length(); } + virtual HValue* OperandAt(int index) const { return values_[index]; } - private: - HArgumentsObject(int count, Zone* zone) - : HDematerializedObject(count, zone) { - set_representation(Representation::Tagged()); - SetFlag(kIsArguments); + virtual bool HasEscapingOperandAt(int index) { return false; } + virtual Representation RequiredInputRepresentation(int index) { + return Representation::None(); } -}; + DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject) -class HCapturedObject: public HDematerializedObject { - public: - HCapturedObject(int length, Zone* zone) - : HDematerializedObject(length, zone) { + protected: + virtual void InternalSetOperandAt(int index, HValue* value) { + values_[index] = value; + } + + private: + HArgumentsObject(int count, Zone* zone) : values_(count, zone) { set_representation(Representation::Tagged()); - values_.AddBlock(NULL, length, zone); // Resize list. + SetFlag(kIsArguments); } - // The values contain a list of all in-object properties inside the - // captured object and is index by field index. Properties in the - // properties or elements backing store are not tracked here. - const ZoneList<HValue*>* values() const { return &values_; } - int length() const { return values_.length(); } + virtual bool IsDeletable() const { return true; } - DECLARE_CONCRETE_INSTRUCTION(CapturedObject) + ZoneList<HValue*> values_; }; @@ -3230,9 +3685,8 @@ class HConstant: public HTemplateInstruction<0> { } bool InstanceOf(Handle<Map> map) { - Handle<Object> constant_object = handle(); - return constant_object->IsJSObject() && - Handle<JSObject>::cast(constant_object)->map() == *map; + return handle_->IsJSObject() && + Handle<JSObject>::cast(handle_)->map() == *map; } bool IsSpecialDouble() const { @@ -3256,9 +3710,6 @@ class HConstant: public HTemplateInstruction<0> { } return false; } - if (has_external_reference_value_) { - return false; - } ASSERT(!handle_.is_null()); Heap* heap = isolate()->heap(); @@ -3343,7 +3794,6 @@ class HConstant: public HTemplateInstruction<0> { return external_reference_value_; } - bool HasBooleanValue() const { return type_.IsBoolean(); } bool BooleanValue() const { return boolean_value_; } virtual intptr_t Hashcode() { @@ -3688,6 +4138,12 @@ class HBoundsCheck: public HTemplateInstruction<2> { HValue* base() { return base_; } int offset() { return offset_; } int scale() { return scale_; } + bool index_can_increase() { + return (responsibility_direction_ & DIRECTION_LOWER) == 0; + } + bool index_can_decrease() { + return (responsibility_direction_ & DIRECTION_UPPER) == 0; + } void ApplyIndexChange(); bool DetectCompoundIndex() { @@ -3711,6 +4167,11 @@ class HBoundsCheck: public HTemplateInstruction<2> { return representation(); } + virtual bool IsRelationTrueInternal(NumericRelation relation, + HValue* related_value, + int offset = 0, + int scale = 0); + virtual void PrintDataTo(StringStream* stream); virtual void InferRepresentation(HInferRepresentationPhase* h_infer); @@ -3721,17 +4182,25 @@ class HBoundsCheck: public HTemplateInstruction<2> { virtual int RedefinedOperandIndex() { return 0; } virtual bool IsPurelyInformativeDefinition() { return skip_check(); } + virtual void AddInformativeDefinitions(); DECLARE_CONCRETE_INSTRUCTION(BoundsCheck) protected: friend class HBoundsCheckBaseIndexInformation; + virtual void SetResponsibilityForRange(RangeGuaranteeDirection direction) { + responsibility_direction_ = static_cast<RangeGuaranteeDirection>( + responsibility_direction_ | direction); + } + virtual bool DataEquals(HValue* other) { return true; } + virtual void TryGuaranteeRangeChanging(RangeEvaluationContext* context); bool skip_check_; HValue* base_; int offset_; int scale_; + RangeGuaranteeDirection responsibility_direction_; bool allow_equality_; private: @@ -3742,6 +4211,7 @@ class HBoundsCheck: public HTemplateInstruction<2> { HBoundsCheck(HValue* index, HValue* length) : skip_check_(false), base_(NULL), offset_(0), scale_(0), + responsibility_direction_(DIRECTION_NONE), allow_equality_(false) { SetOperandAt(0, index); SetOperandAt(1, length); @@ -3776,10 +4246,22 @@ class HBoundsCheckBaseIndexInformation: public HTemplateInstruction<2> { return representation(); } + virtual bool IsRelationTrueInternal(NumericRelation relation, + HValue* related_value, + int offset = 0, + int scale = 0); virtual void PrintDataTo(StringStream* stream); virtual int RedefinedOperandIndex() { return 0; } virtual bool IsPurelyInformativeDefinition() { return true; } + + protected: + virtual void SetResponsibilityForRange(RangeGuaranteeDirection direction) { + bounds_check()->SetResponsibilityForRange(direction); + } + virtual void TryGuaranteeRangeChanging(RangeEvaluationContext* context) { + bounds_check()->TryGuaranteeRangeChanging(context); + } }; @@ -3952,6 +4434,8 @@ class HCompareNumericAndBranch: public HTemplateControlInstruction<2, 2> { } virtual void PrintDataTo(StringStream* stream); + virtual void AddInformativeDefinitions(); + DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch) private: @@ -3960,32 +4444,6 @@ class HCompareNumericAndBranch: public HTemplateControlInstruction<2, 2> { }; -class HCompareHoleAndBranch: public HTemplateControlInstruction<2, 1> { - public: - // TODO(danno): make this private when the IfBuilder properly constructs - // control flow instructions. - explicit HCompareHoleAndBranch(HValue* object) { - SetFlag(kFlexibleRepresentation); - SetFlag(kAllowUndefinedAsNaN); - SetOperandAt(0, object); - } - - DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*); - - HValue* object() { return OperandAt(0); } - - virtual void InferRepresentation(HInferRepresentationPhase* h_infer); - - virtual Representation RequiredInputRepresentation(int index) { - return representation(); - } - - virtual void PrintDataTo(StringStream* stream); - - DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch) -}; - - class HCompareObjectEqAndBranch: public HTemplateControlInstruction<2, 2> { public: // TODO(danno): make this private when the IfBuilder properly constructs @@ -4369,11 +4827,6 @@ class HAdd: public HArithmeticBinaryOperation { } } - virtual void RepresentationChanged(Representation to) { - if (to.IsTagged()) ClearFlag(kAllowUndefinedAsNaN); - HArithmeticBinaryOperation::RepresentationChanged(to); - } - DECLARE_CONCRETE_INSTRUCTION(Add) protected: @@ -5588,7 +6041,6 @@ class HLoadNamedField: public HTemplateInstruction<2> { } bool HasTypeCheck() const { return OperandAt(0) != OperandAt(1); } - void ClearTypeCheck() { SetOperandAt(1, object()); } HObjectAccess access() const { return access_; } Representation field_representation() const { return access_.representation(); @@ -5646,6 +6098,45 @@ class HLoadNamedField: public HTemplateInstruction<2> { }; +class HLoadNamedFieldPolymorphic: public HTemplateInstruction<2> { + public: + HLoadNamedFieldPolymorphic(HValue* context, + HValue* object, + SmallMapList* types, + Handle<String> name, + Zone* zone); + + HValue* context() { return OperandAt(0); } + HValue* object() { return OperandAt(1); } + SmallMapList* types() { return &types_; } + Handle<String> name() { return name_; } + bool need_generic() { return need_generic_; } + + virtual Representation RequiredInputRepresentation(int index) { + return Representation::Tagged(); + } + + virtual void PrintDataTo(StringStream* stream); + + DECLARE_CONCRETE_INSTRUCTION(LoadNamedFieldPolymorphic) + + static const int kMaxLoadPolymorphism = 4; + + virtual void FinalizeUniqueValueId(); + + protected: + virtual bool DataEquals(HValue* value); + + private: + SmallMapList types_; + Handle<String> name_; + ZoneList<UniqueValueId> types_unique_ids_; + UniqueValueId name_unique_id_; + bool need_generic_; +}; + + + class HLoadNamedGeneric: public HTemplateInstruction<2> { public: HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name) @@ -5904,7 +6395,7 @@ class HLoadKeyedGeneric: public HTemplateInstruction<3> { }; -class HStoreNamedField: public HTemplateInstruction<3> { +class HStoreNamedField: public HTemplateInstruction<2> { public: DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*, HObjectAccess, HValue*); @@ -5936,35 +6427,24 @@ class HStoreNamedField: public HTemplateInstruction<3> { return write_barrier_mode_ == SKIP_WRITE_BARRIER; } - HValue* object() const { return OperandAt(0); } - HValue* value() const { return OperandAt(1); } - HValue* transition() const { return OperandAt(2); } + HValue* object() { return OperandAt(0); } + HValue* value() { return OperandAt(1); } HObjectAccess access() const { return access_; } - HValue* new_space_dominator() const { return new_space_dominator_; } - bool has_transition() const { return has_transition_; } - - Handle<Map> transition_map() const { - if (has_transition()) { - return Handle<Map>::cast(HConstant::cast(transition())->handle()); - } else { - return Handle<Map>(); - } - } - - void SetTransition(HConstant* map_constant, CompilationInfo* info) { - ASSERT(!has_transition()); // Only set once. - Handle<Map> map = Handle<Map>::cast(map_constant->handle()); + Handle<Map> transition() const { return transition_; } + UniqueValueId transition_unique_id() const { return transition_unique_id_; } + void SetTransition(Handle<Map> map, CompilationInfo* info) { + ASSERT(transition_.is_null()); // Only set once. if (map->CanBeDeprecated()) { map->AddDependentCompilationInfo(DependentCode::kTransitionGroup, info); } - SetOperandAt(2, map_constant); - has_transition_ = true; + transition_ = map; } + HValue* new_space_dominator() const { return new_space_dominator_; } bool NeedsWriteBarrier() { ASSERT(!(FLAG_track_double_fields && field_representation().IsDouble()) || - !has_transition()); + transition_.is_null()); if (IsSkipWriteBarrier()) return false; if (field_representation().IsDouble()) return false; if (field_representation().IsSmi()) return false; @@ -5979,6 +6459,10 @@ class HStoreNamedField: public HTemplateInstruction<3> { return ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator()); } + virtual void FinalizeUniqueValueId() { + transition_unique_id_ = UniqueValueId(transition_); + } + Representation field_representation() const { return access_.representation(); } @@ -5988,19 +6472,20 @@ class HStoreNamedField: public HTemplateInstruction<3> { HObjectAccess access, HValue* val) : access_(access), + transition_(), + transition_unique_id_(), new_space_dominator_(NULL), - write_barrier_mode_(UPDATE_WRITE_BARRIER), - has_transition_(false) { + write_barrier_mode_(UPDATE_WRITE_BARRIER) { SetOperandAt(0, obj); SetOperandAt(1, val); - SetOperandAt(2, obj); access.SetGVNFlags(this, true); } HObjectAccess access_; + Handle<Map> transition_; + UniqueValueId transition_unique_id_; HValue* new_space_dominator_; - WriteBarrierMode write_barrier_mode_ : 1; - bool has_transition_ : 1; + WriteBarrierMode write_barrier_mode_; }; @@ -6045,6 +6530,7 @@ class HStoreKeyed DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*, ElementsKind); + virtual bool HasEscapingOperandAt(int index) { return index != 0; } virtual Representation RequiredInputRepresentation(int index) { // kind_fast: tagged[int32] = tagged // kind_double: tagged[int32] = double @@ -6563,11 +7049,8 @@ class HToFastProperties: public HUnaryOperation { private: explicit HToFastProperties(HValue* value) : HUnaryOperation(value) { - set_representation(Representation::Tagged()); - SetGVNFlag(kChangesNewSpacePromotion); - - // This instruction is not marked as kChangesMaps, but does - // change the map of the input operand. Use it only when creating + // This instruction is not marked as having side effects, but + // changes the map of the input operand. Use it only when creating // object literals via a runtime call. ASSERT(value->IsCallRuntime()); #ifdef DEBUG @@ -6575,6 +7058,7 @@ class HToFastProperties: public HUnaryOperation { ASSERT(function->function_id == Runtime::kCreateObjectLiteral || function->function_id == Runtime::kCreateObjectLiteralShallow); #endif + set_representation(Representation::Tagged()); } virtual bool IsDeletable() const { return true; } diff --git a/chromium/v8/src/hydrogen-mark-deoptimize.cc b/chromium/v8/src/hydrogen-mark-deoptimize.cc index c0236e91cbb..111fcd2ce9b 100644 --- a/chromium/v8/src/hydrogen-mark-deoptimize.cc +++ b/chromium/v8/src/hydrogen-mark-deoptimize.cc @@ -34,9 +34,14 @@ void HMarkDeoptimizeOnUndefinedPhase::Run() { const ZoneList<HPhi*>* phi_list = graph()->phi_list(); for (int i = 0; i < phi_list->length(); i++) { HPhi* phi = phi_list->at(i); - if (phi->CheckFlag(HValue::kAllowUndefinedAsNaN) && - !phi->CheckUsesForFlag(HValue::kAllowUndefinedAsNaN)) { - ProcessPhi(phi); + if (phi->CheckFlag(HValue::kAllowUndefinedAsNaN)) { + for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) { + HValue* use_value = it.value(); + if (!use_value->CheckFlag(HValue::kAllowUndefinedAsNaN)) { + ProcessPhi(phi); + break; + } + } } } } @@ -63,22 +68,4 @@ void HMarkDeoptimizeOnUndefinedPhase::ProcessPhi(HPhi* phi) { } } - -void HComputeChangeUndefinedToNaN::Run() { - const ZoneList<HBasicBlock*>* blocks(graph()->blocks()); - for (int i = 0; i < blocks->length(); ++i) { - const HBasicBlock* block(blocks->at(i)); - for (HInstruction* current = block->first(); current != NULL; ) { - HInstruction* next = current->next(); - if (current->IsChange()) { - if (HChange::cast(current)->can_convert_undefined_to_nan()) { - current->SetFlag(HValue::kAllowUndefinedAsNaN); - } - } - current = next; - } - } -} - - } } // namespace v8::internal diff --git a/chromium/v8/src/hydrogen-mark-deoptimize.h b/chromium/v8/src/hydrogen-mark-deoptimize.h index 30f35b3dec5..0aa2c2c7540 100644 --- a/chromium/v8/src/hydrogen-mark-deoptimize.h +++ b/chromium/v8/src/hydrogen-mark-deoptimize.h @@ -58,18 +58,6 @@ class HMarkDeoptimizeOnUndefinedPhase : public HPhase { }; -class HComputeChangeUndefinedToNaN : public HPhase { - public: - explicit HComputeChangeUndefinedToNaN(HGraph* graph) - : HPhase("H_Compute change undefined to nan", graph) {} - - void Run(); - - private: - DISALLOW_COPY_AND_ASSIGN(HComputeChangeUndefinedToNaN); -}; - - } } // namespace v8::internal #endif // V8_HYDROGEN_MARK_DEOPTIMIZE_H_ diff --git a/chromium/v8/src/hydrogen-representation-changes.cc b/chromium/v8/src/hydrogen-representation-changes.cc index 862457db38c..63b7b4d6ec8 100644 --- a/chromium/v8/src/hydrogen-representation-changes.cc +++ b/chromium/v8/src/hydrogen-representation-changes.cc @@ -47,6 +47,8 @@ void HRepresentationChangesPhase::InsertRepresentationChangeForUse( HInstruction* new_value = NULL; bool is_truncating_to_smi = use_value->CheckFlag(HValue::kTruncatingToSmi); bool is_truncating_to_int = use_value->CheckFlag(HValue::kTruncatingToInt32); + bool allow_undefined_as_nan = + use_value->CheckFlag(HValue::kAllowUndefinedAsNaN); if (value->IsConstant()) { HConstant* constant = HConstant::cast(value); // Try to create a new copy of the constant with the new representation. @@ -59,8 +61,10 @@ void HRepresentationChangesPhase::InsertRepresentationChangeForUse( } if (new_value == NULL) { - new_value = new(graph()->zone()) HChange( - value, to, is_truncating_to_smi, is_truncating_to_int); + new_value = new(graph()->zone()) HChange(value, to, + is_truncating_to_smi, + is_truncating_to_int, + allow_undefined_as_nan); } new_value->InsertBefore(next); @@ -123,7 +127,7 @@ void HRepresentationChangesPhase::Run() { !(input_representation.IsInteger32() && use->CheckFlag(HValue::kTruncatingToInt32))) || (phi->representation().IsSmi() && - !(input_representation.IsSmi() && + !(input_representation.IsSmi() || use->CheckFlag(HValue::kTruncatingToSmi)))) { if (FLAG_trace_representation) { PrintF("#%d Phi is not truncating because of #%d %s\n", diff --git a/chromium/v8/src/hydrogen-uint32-analysis.cc b/chromium/v8/src/hydrogen-uint32-analysis.cc index 835a198d4d8..67219f55dff 100644 --- a/chromium/v8/src/hydrogen-uint32-analysis.cc +++ b/chromium/v8/src/hydrogen-uint32-analysis.cc @@ -33,7 +33,11 @@ namespace internal { bool HUint32AnalysisPhase::IsSafeUint32Use(HValue* val, HValue* use) { // Operations that operate on bits are safe. - if (use->IsBitwise() || use->IsShl() || use->IsSar() || use->IsShr()) { + if (use->IsBitwise() || + use->IsShl() || + use->IsSar() || + use->IsShr() || + use->IsBitNot()) { return true; } else if (use->IsChange() || use->IsSimulate()) { // Conversions and deoptimization have special support for unt32. diff --git a/chromium/v8/src/hydrogen.cc b/chromium/v8/src/hydrogen.cc index ba1de7aa225..aab64d64d45 100644 --- a/chromium/v8/src/hydrogen.cc +++ b/chromium/v8/src/hydrogen.cc @@ -834,14 +834,14 @@ void HGraphBuilder::IfBuilder::Else() { } -void HGraphBuilder::IfBuilder::Deopt(const char* reason) { +void HGraphBuilder::IfBuilder::Deopt() { ASSERT(did_then_); if (did_else_) { deopt_else_ = true; } else { deopt_then_ = true; } - builder_->Add<HDeoptimize>(reason, Deoptimizer::EAGER); + builder_->Add<HDeoptimize>(Deoptimizer::EAGER); } @@ -966,9 +966,8 @@ void HGraphBuilder::LoopBuilder::EndBody() { // Push the new increment value on the expression stack to merge into the phi. builder_->environment()->Push(increment_); - HBasicBlock* last_block = builder_->current_block(); - last_block->GotoNoSimulate(header_block_); - header_block_->loop_information()->RegisterBackEdge(last_block); + builder_->current_block()->GotoNoSimulate(header_block_); + header_block_->loop_information()->RegisterBackEdge(body_block_); builder_->set_current_block(exit_block_); // Pop the phi from the expression stack @@ -1043,9 +1042,9 @@ HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) { void HGraphBuilder::FinishExitWithHardDeoptimization( - const char* reason, HBasicBlock* continuation) { + HBasicBlock* continuation) { PadEnvironmentForContinuation(current_block(), continuation); - Add<HDeoptimize>(reason, Deoptimizer::EAGER); + Add<HDeoptimize>(Deoptimizer::EAGER); if (graph()->IsInsideNoSideEffectsScope()) { current_block()->GotoNoSimulate(continuation); } else { @@ -1059,14 +1058,12 @@ void HGraphBuilder::PadEnvironmentForContinuation( HBasicBlock* continuation) { if (continuation->last_environment() != NULL) { // When merging from a deopt block to a continuation, resolve differences in - // environment by pushing constant 0 and popping extra values so that the - // environments match during the join. Push 0 since it has the most specific - // representation, and will not influence representation inference of the - // phi. + // environment by pushing undefined and popping extra values so that the + // environments match during the join. int continuation_env_length = continuation->last_environment()->length(); while (continuation_env_length != from->last_environment()->length()) { if (continuation_env_length > from->last_environment()->length()) { - from->last_environment()->Push(graph()->GetConstant0()); + from->last_environment()->Push(graph()->GetConstantUndefined()); } else { from->last_environment()->Pop(); } @@ -1117,7 +1114,7 @@ HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object, IfBuilder key_checker(this); key_checker.If<HCompareNumericAndBranch>(key, max_capacity, Token::LT); key_checker.Then(); - key_checker.ElseDeopt("Key out of capacity range"); + key_checker.ElseDeopt(); key_checker.End(); HValue* new_capacity = BuildNewElementsCapacity(key); @@ -1273,7 +1270,7 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( negative_checker.Then(); HInstruction* result = AddExternalArrayElementAccess( external_elements, key, val, bounds_check, elements_kind, is_store); - negative_checker.ElseDeopt("Negative key encountered"); + negative_checker.ElseDeopt(); length_checker.End(); return result; } else { @@ -1635,26 +1632,13 @@ void HGraphBuilder::BuildCopyElements(HValue* from_elements, from_elements_kind, ALLOW_RETURN_HOLE); - ElementsKind kind = (IsHoleyElementsKind(from_elements_kind) && - IsFastSmiElementsKind(to_elements_kind)) + ElementsKind holey_kind = IsFastSmiElementsKind(to_elements_kind) ? FAST_HOLEY_ELEMENTS : to_elements_kind; - - if (IsHoleyElementsKind(from_elements_kind) && - from_elements_kind != to_elements_kind) { - IfBuilder if_hole(this); - if_hole.If<HCompareHoleAndBranch>(element); - if_hole.Then(); - HConstant* hole_constant = IsFastDoubleElementsKind(to_elements_kind) - ? Add<HConstant>(FixedDoubleArray::hole_nan_as_double()) - : graph()->GetConstantHole(); - Add<HStoreKeyed>(to_elements, key, hole_constant, kind); - if_hole.Else(); - HStoreKeyed* store = Add<HStoreKeyed>(to_elements, key, element, kind); - store->SetFlag(HValue::kAllowUndefinedAsNaN); - if_hole.End(); - } else { - HStoreKeyed* store = Add<HStoreKeyed>(to_elements, key, element, kind); - store->SetFlag(HValue::kAllowUndefinedAsNaN); + HInstruction* holey_store = Add<HStoreKeyed>(to_elements, key, + element, holey_kind); + // Allow NaN hole values to converted to their tagged counterparts. + if (IsFastHoleyElementsKind(to_elements_kind)) { + holey_store->SetFlag(HValue::kAllowUndefinedAsNaN); } builder.EndBody(); @@ -1741,6 +1725,38 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HValue* boilerplate, } +HInstruction* HGraphBuilder::BuildUnaryMathOp( + HValue* input, Handle<Type> type, Token::Value operation) { + // We only handle the numeric cases here + type = handle( + Type::Intersect(type, handle(Type::Number(), isolate())), isolate()); + + switch (operation) { + default: + UNREACHABLE(); + case Token::SUB: { + HInstruction* instr = + NewUncasted<HMul>(input, graph()->GetConstantMinus1()); + Representation rep = Representation::FromType(type); + if (type->Is(Type::None())) { + Add<HDeoptimize>(Deoptimizer::SOFT); + } + if (instr->IsBinaryOperation()) { + HBinaryOperation* binop = HBinaryOperation::cast(instr); + binop->set_observed_input_representation(1, rep); + binop->set_observed_input_representation(2, rep); + } + return instr; + } + case Token::BIT_NOT: + if (type->Is(Type::None())) { + Add<HDeoptimize>(Deoptimizer::SOFT); + } + return New<HBitNot>(input); + } +} + + void HGraphBuilder::BuildCompareNil( HValue* value, Handle<Type> type, @@ -1773,7 +1789,7 @@ void HGraphBuilder::BuildCompareNil( // emitted below is the actual monomorphic map. BuildCheckMap(value, type->Classes().Current()); } else { - if_nil.Deopt("Too many undetectable types"); + if_nil.Deopt(); } } @@ -2572,7 +2588,7 @@ void ValueContext::ReturnValue(HValue* value) { // The value is tracked in the bailout environment, and communicated // through the environment as the result of the expression. if (!arguments_allowed() && value->CheckFlag(HValue::kIsArguments)) { - owner()->Bailout(kBadValueContextForArgumentsValue); + owner()->Bailout("bad value context for arguments value"); } owner()->Push(value); } @@ -2624,7 +2640,7 @@ void EffectContext::ReturnContinuation(HIfContinuation* continuation, void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { ASSERT(!instr->IsControlInstruction()); if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) { - return owner()->Bailout(kBadValueContextForArgumentsObjectValue); + return owner()->Bailout("bad value context for arguments object value"); } owner()->AddInstruction(instr); owner()->Push(instr); @@ -2637,7 +2653,7 @@ void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { void ValueContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) { ASSERT(!instr->HasObservableSideEffects()); if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) { - return owner()->Bailout(kBadValueContextForArgumentsObjectValue); + return owner()->Bailout("bad value context for arguments object value"); } HBasicBlock* materialize_false = owner()->graph()->CreateBasicBlock(); HBasicBlock* materialize_true = owner()->graph()->CreateBasicBlock(); @@ -2727,7 +2743,7 @@ void TestContext::BuildBranch(HValue* value) { // branch. HOptimizedGraphBuilder* builder = owner(); if (value != NULL && value->CheckFlag(HValue::kIsArguments)) { - builder->Bailout(kArgumentsObjectValueInATestContext); + builder->Bailout("arguments object value in a test context"); } if (value->IsConstant()) { HConstant* constant_value = HConstant::cast(value); @@ -2773,7 +2789,7 @@ void TestContext::BuildBranch(HValue* value) { } while (false) -void HOptimizedGraphBuilder::Bailout(BailoutReason reason) { +void HOptimizedGraphBuilder::Bailout(const char* reason) { current_info()->set_bailout_reason(reason); SetStackOverflow(); } @@ -2832,16 +2848,16 @@ void HOptimizedGraphBuilder::VisitExpressions( bool HOptimizedGraphBuilder::BuildGraph() { if (current_info()->function()->is_generator()) { - Bailout(kFunctionIsAGenerator); + Bailout("function is a generator"); return false; } Scope* scope = current_info()->scope(); if (scope->HasIllegalRedeclaration()) { - Bailout(kFunctionWithIllegalRedeclaration); + Bailout("function with illegal redeclaration"); return false; } if (scope->calls_eval()) { - Bailout(kFunctionCallsEval); + Bailout("function calls eval"); return false; } SetUpScope(scope); @@ -2907,7 +2923,8 @@ bool HOptimizedGraphBuilder::BuildGraph() { } -bool HGraph::Optimize(BailoutReason* bailout_reason) { +bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) { + *bailout_reason = SmartArrayPointer<char>(); OrderBlocks(); AssignDominators(); @@ -2928,20 +2945,19 @@ bool HGraph::Optimize(BailoutReason* bailout_reason) { Run<HPropagateDeoptimizingMarkPhase>(); if (!CheckConstPhiUses()) { - *bailout_reason = kUnsupportedPhiUseOfConstVariable; + *bailout_reason = SmartArrayPointer<char>(StrDup( + "Unsupported phi use of const variable")); return false; } Run<HRedundantPhiEliminationPhase>(); if (!CheckArgumentsPhiUses()) { - *bailout_reason = kUnsupportedPhiUseOfArguments; + *bailout_reason = SmartArrayPointer<char>(StrDup( + "Unsupported phi use of arguments")); return false; } // Remove dead code and phis if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>(); - - if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>(); - CollectPhis(); if (has_osr()) osr()->FinishOsrValues(); @@ -2965,20 +2981,22 @@ bool HGraph::Optimize(BailoutReason* bailout_reason) { if (FLAG_use_canonicalizing) Run<HCanonicalizePhase>(); + if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>(); + if (FLAG_use_gvn) Run<HGlobalValueNumberingPhase>(); if (FLAG_use_range) Run<HRangeAnalysisPhase>(); - Run<HComputeChangeUndefinedToNaN>(); Run<HComputeMinusZeroChecksPhase>(); // Eliminate redundant stack checks on backwards branches. Run<HStackCheckEliminationPhase>(); - if (FLAG_array_bounds_checks_elimination) { + if (FLAG_idefs) SetupInformativeDefinitions(); + if (FLAG_array_bounds_checks_elimination && !FLAG_idefs) { Run<HBoundsCheckEliminationPhase>(); } - if (FLAG_array_bounds_checks_hoisting) { + if (FLAG_array_bounds_checks_hoisting && !FLAG_idefs) { Run<HBoundsCheckHoistingPhase>(); } if (FLAG_array_index_dehoisting) Run<HDehoistIndexComputationsPhase>(); @@ -2990,6 +3008,50 @@ bool HGraph::Optimize(BailoutReason* bailout_reason) { } +void HGraph::SetupInformativeDefinitionsInBlock(HBasicBlock* block) { + for (int phi_index = 0; phi_index < block->phis()->length(); phi_index++) { + HPhi* phi = block->phis()->at(phi_index); + phi->AddInformativeDefinitions(); + phi->SetFlag(HValue::kIDefsProcessingDone); + // We do not support phis that "redefine just one operand". + ASSERT(!phi->IsInformativeDefinition()); + } + + for (HInstructionIterator it(block); !it.Done(); it.Advance()) { + HInstruction* i = it.Current(); + i->AddInformativeDefinitions(); + i->SetFlag(HValue::kIDefsProcessingDone); + i->UpdateRedefinedUsesWhileSettingUpInformativeDefinitions(); + } +} + + +// This method is recursive, so if its stack frame is large it could +// cause a stack overflow. +// To keep the individual stack frames small we do the actual work inside +// SetupInformativeDefinitionsInBlock(); +void HGraph::SetupInformativeDefinitionsRecursively(HBasicBlock* block) { + SetupInformativeDefinitionsInBlock(block); + for (int i = 0; i < block->dominated_blocks()->length(); ++i) { + SetupInformativeDefinitionsRecursively(block->dominated_blocks()->at(i)); + } + + for (HInstructionIterator it(block); !it.Done(); it.Advance()) { + HInstruction* i = it.Current(); + if (i->IsBoundsCheck()) { + HBoundsCheck* check = HBoundsCheck::cast(i); + check->ApplyIndexChange(); + } + } +} + + +void HGraph::SetupInformativeDefinitions() { + HPhase phase("H_Setup informative definitions", this); + SetupInformativeDefinitionsRecursively(entry_block()); +} + + void HGraph::RestoreActualValues() { HPhase phase("H_Restore actual values", this); @@ -3072,7 +3134,7 @@ void HOptimizedGraphBuilder::SetUpScope(Scope* scope) { // not have declarations). if (scope->arguments() != NULL) { if (!scope->arguments()->IsStackAllocated()) { - return Bailout(kContextAllocatedArguments); + return Bailout("context-allocated arguments"); } environment()->Bind(scope->arguments(), @@ -3093,7 +3155,7 @@ void HOptimizedGraphBuilder::VisitBlock(Block* stmt) { ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); if (stmt->scope() != NULL) { - return Bailout(kScopedBlock); + return Bailout("ScopedBlock"); } BreakAndContinueInfo break_info(stmt); { BreakAndContinueScope push(&break_info, this); @@ -3305,7 +3367,7 @@ void HOptimizedGraphBuilder::VisitWithStatement(WithStatement* stmt) { ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); - return Bailout(kWithStatement); + return Bailout("WithStatement"); } @@ -3320,12 +3382,12 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { ZoneList<CaseClause*>* clauses = stmt->cases(); int clause_count = clauses->length(); if (clause_count > kCaseClauseLimit) { - return Bailout(kSwitchStatementTooManyClauses); + return Bailout("SwitchStatement: too many clauses"); } ASSERT(stmt->switch_type() != SwitchStatement::UNKNOWN_SWITCH); if (stmt->switch_type() == SwitchStatement::GENERIC_SWITCH) { - return Bailout(kSwitchStatementMixedOrNonLiteralSwitchLabels); + return Bailout("SwitchStatement: mixed or non-literal switch labels"); } HValue* context = environment()->context(); @@ -3371,7 +3433,7 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { if (stmt->switch_type() == SwitchStatement::SMI_SWITCH) { if (!clause->compare_type()->Is(Type::Smi())) { - Add<HDeoptimize>("Non-smi switch type", Deoptimizer::SOFT); + Add<HDeoptimize>(Deoptimizer::SOFT); } HCompareNumericAndBranch* compare_ = @@ -3617,16 +3679,16 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) { ASSERT(current_block()->HasPredecessor()); if (!FLAG_optimize_for_in) { - return Bailout(kForInStatementOptimizationIsDisabled); + return Bailout("ForInStatement optimization is disabled"); } if (stmt->for_in_type() != ForInStatement::FAST_FOR_IN) { - return Bailout(kForInStatementIsNotFastCase); + return Bailout("ForInStatement is not fast case"); } if (!stmt->each()->IsVariableProxy() || !stmt->each()->AsVariableProxy()->var()->IsStackLocal()) { - return Bailout(kForInStatementWithNonLocalEachVariable); + return Bailout("ForInStatement with non-local each variable"); } Variable* each_var = stmt->each()->AsVariableProxy()->var(); @@ -3720,7 +3782,7 @@ void HOptimizedGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) { ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); - return Bailout(kForOfStatement); + return Bailout("ForOfStatement"); } @@ -3728,7 +3790,7 @@ void HOptimizedGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); - return Bailout(kTryCatchStatement); + return Bailout("TryCatchStatement"); } @@ -3737,7 +3799,7 @@ void HOptimizedGraphBuilder::VisitTryFinallyStatement( ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); - return Bailout(kTryFinallyStatement); + return Bailout("TryFinallyStatement"); } @@ -3745,7 +3807,7 @@ void HOptimizedGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); - return Bailout(kDebuggerStatement); + return Bailout("DebuggerStatement"); } @@ -3791,7 +3853,7 @@ void HOptimizedGraphBuilder::VisitSharedFunctionInfoLiteral( ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); - return Bailout(kSharedFunctionInfoLiteral); + return Bailout("SharedFunctionInfoLiteral"); } @@ -3871,7 +3933,7 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { case Variable::UNALLOCATED: { if (IsLexicalVariableMode(variable->mode())) { // TODO(rossberg): should this be an ASSERT? - return Bailout(kReferenceToGlobalLexicalVariable); + return Bailout("reference to global lexical variable"); } // Handle known global constants like 'undefined' specially to avoid a // load from a global cell for them. @@ -3928,7 +3990,7 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { if (value == graph()->GetConstantHole()) { ASSERT(IsDeclaredVariableMode(variable->mode()) && variable->mode() != VAR); - return Bailout(kReferenceToUninitializedVariable); + return Bailout("reference to uninitialized variable"); } return ast_context()->ReturnValue(value); } @@ -3940,7 +4002,7 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { } case Variable::LOOKUP: - return Bailout(kReferenceToAVariableWhichRequiresDynamicLookup); + return Bailout("reference to a variable which requires dynamic lookup"); } } @@ -4061,7 +4123,8 @@ static bool IsFastLiteral(Handle<JSObject> boilerplate, int* data_size, int* pointer_size) { if (boilerplate->map()->is_deprecated()) { - Handle<Object> result = JSObject::TryMigrateInstance(boilerplate); + Handle<Object> result = + JSObject::TryMigrateInstance(boilerplate); if (result->IsSmi()) return false; } @@ -4238,7 +4301,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { case ObjectLiteral::Property::PROTOTYPE: case ObjectLiteral::Property::SETTER: case ObjectLiteral::Property::GETTER: - return Bailout(kObjectLiteralWithComplexProperty); + return Bailout("Object literal with complex property"); default: UNREACHABLE(); } } @@ -4277,7 +4340,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { raw_boilerplate = Runtime::CreateArrayLiteralBoilerplate( isolate(), literals, expr->constant_elements()); if (raw_boilerplate.is_null()) { - return Bailout(kArrayBoilerplateCreationFailed); + return Bailout("array boilerplate creation failed"); } site = isolate()->factory()->NewAllocationSite(); @@ -4369,7 +4432,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { CHECK_ALIVE(VisitForValue(subexpr)); HValue* value = Pop(); - if (!Smi::IsValid(i)) return Bailout(kNonSmiKeyInArrayLiteral); + if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal"); elements = AddLoadElements(literal, type_check); @@ -4450,7 +4513,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( if (proto_result.IsProperty()) { // If the inherited property could induce readonly-ness, bail out. if (proto_result.IsReadOnly() || !proto_result.IsCacheable()) { - Bailout(kImproperObjectOnPrototypeChainForStore); + Bailout("improper object on prototype chain for store"); return NULL; } // We only need to check up to the preexisting property. @@ -4463,9 +4526,9 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( ASSERT(proto->GetPrototype(isolate())->IsNull()); } ASSERT(proto->IsJSObject()); - BuildCheckPrototypeMaps( + Add<HCheckPrototypeMaps>( Handle<JSObject>(JSObject::cast(map->prototype())), - Handle<JSObject>(JSObject::cast(proto))); + Handle<JSObject>(JSObject::cast(proto)), top_info()); } HObjectAccess field_access = HObjectAccess::ForField(map, lookup, name); @@ -4503,8 +4566,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( if (transition_to_field) { Handle<Map> transition(lookup->GetTransitionMapFromMap(*map)); - HConstant* transition_constant = Add<HConstant>(transition); - instr->SetTransition(transition_constant, top_info()); + instr->SetTransition(transition, top_info()); // TODO(fschneider): Record the new map type of the object in the IR to // enable elimination of redundant checks after the transition store. instr->SetGVNFlag(kChangesMaps); @@ -4620,43 +4682,14 @@ HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic( Handle<JSObject> holder(lookup.holder()); Handle<Map> holder_map(holder->map()); - BuildCheckPrototypeMaps(Handle<JSObject>::cast(prototype), holder); + Add<HCheckPrototypeMaps>( + Handle<JSObject>::cast(prototype), holder, top_info()); HValue* holder_value = Add<HConstant>(holder); return BuildLoadNamedField(holder_value, HObjectAccess::ForField(holder_map, &lookup, name), type_check); } -// Returns true if an instance of this map can never find a property with this -// name in its prototype chain. This means all prototypes up to the top are -// fast and don't have the name in them. It would be good if we could optimize -// polymorphic loads where the property is sometimes found in the prototype -// chain. -static bool PrototypeChainCanNeverResolve( - Handle<Map> map, Handle<String> name) { - Isolate* isolate = map->GetIsolate(); - Object* current = map->prototype(); - while (current != isolate->heap()->null_value()) { - if (current->IsJSGlobalProxy() || - current->IsGlobalObject() || - !current->IsJSObject() || - JSObject::cast(current)->map()->has_named_interceptor() || - JSObject::cast(current)->IsAccessCheckNeeded() || - !JSObject::cast(current)->HasFastProperties()) { - return false; - } - - LookupResult lookup(isolate); - Map* map = JSObject::cast(current)->map(); - map->LookupDescriptor(NULL, *name, &lookup); - if (lookup.IsFound()) return false; - if (!lookup.IsCacheable()) return false; - current = JSObject::cast(current)->GetPrototype(); - } - return true; -} - - void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( Property* expr, HValue* object, @@ -4664,90 +4697,16 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( Handle<String> name) { HInstruction* instr = TryLoadPolymorphicAsMonomorphic( expr, object, types, name); - if (instr != NULL) { - instr->set_position(expr->position()); - return ast_context()->ReturnInstruction(instr, expr->id()); - } - - // Something did not match; must use a polymorphic load. - int count = 0; - HBasicBlock* join = NULL; - for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { - Handle<Map> map = types->at(i); - LookupResult lookup(isolate()); - if (ComputeLoadStoreField(map, name, &lookup, false) || - (lookup.IsCacheable() && - !map->is_dictionary_map() && - !map->has_named_interceptor() && - (lookup.IsConstant() || - (!lookup.IsFound() && - PrototypeChainCanNeverResolve(map, name))))) { - if (count == 0) { - BuildCheckHeapObject(object); - join = graph()->CreateBasicBlock(); - } - ++count; - HBasicBlock* if_true = graph()->CreateBasicBlock(); - HBasicBlock* if_false = graph()->CreateBasicBlock(); - HCompareMap* compare = - new(zone()) HCompareMap(object, map, if_true, if_false); - current_block()->Finish(compare); - - set_current_block(if_true); - - // TODO(verwaest): Merge logic with BuildLoadNamedMonomorphic. - if (lookup.IsField()) { - HObjectAccess access = HObjectAccess::ForField(map, &lookup, name); - HLoadNamedField* load = BuildLoadNamedField(object, access, compare); - load->set_position(expr->position()); - AddInstruction(load); - if (!ast_context()->IsEffect()) Push(load); - } else if (lookup.IsConstant()) { - Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate()); - HConstant* hconstant = Add<HConstant>(constant); - if (!ast_context()->IsEffect()) Push(hconstant); - } else { - ASSERT(!lookup.IsFound()); - if (map->prototype()->IsJSObject()) { - Handle<JSObject> prototype(JSObject::cast(map->prototype())); - Handle<JSObject> holder = prototype; - while (holder->map()->prototype()->IsJSObject()) { - holder = handle(JSObject::cast(holder->map()->prototype())); - } - BuildCheckPrototypeMaps(prototype, holder); - } - if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined()); - } - - current_block()->Goto(join); - set_current_block(if_false); - } - } - - // Finish up. Unconditionally deoptimize if we've handled all the maps we - // know about and do not want to handle ones we've never seen. Otherwise - // use a generic IC. - if (count == types->length() && FLAG_deoptimize_uncommon_cases) { - FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join); - } else { - HInstruction* load = BuildLoadNamedGeneric(object, name, expr); - load->set_position(expr->position()); - AddInstruction(load); - if (!ast_context()->IsEffect()) Push(load); - - if (join != NULL) { - current_block()->Goto(join); - } else { - Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); - if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); - return; - } + if (instr == NULL) { + // Something did not match; must use a polymorphic load. + BuildCheckHeapObject(object); + HValue* context = environment()->context(); + instr = new(zone()) HLoadNamedFieldPolymorphic( + context, object, types, name, zone()); } - ASSERT(join != NULL); - join->SetJoinId(expr->id()); - set_current_block(join); - if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); + instr->set_position(expr->position()); + return ast_context()->ReturnInstruction(instr, expr->id()); } @@ -4866,7 +4825,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( // know about and do not want to handle ones we've never seen. Otherwise // use a generic IC. if (count == types->length() && FLAG_deoptimize_uncommon_cases) { - FinishExitWithHardDeoptimization("Unknown map in polymorphic store", join); + FinishExitWithHardDeoptimization(join); } else { HInstruction* instr = BuildStoreNamedGeneric(object, name, store_value); instr->set_position(position); @@ -4914,10 +4873,7 @@ void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) { HValue* value = environment()->ExpressionStackAt(0); HValue* object = environment()->ExpressionStackAt(1); - if (expr->IsUninitialized()) { - Add<HDeoptimize>("Insufficient type feedback for property assignment", - Deoptimizer::SOFT); - } + if (expr->IsUninitialized()) Add<HDeoptimize>(Deoptimizer::SOFT); return BuildStoreNamed(expr, expr->id(), expr->position(), expr->AssignmentId(), prop, object, value, value); } else { @@ -4963,8 +4919,7 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( } builder.Then(); builder.Else(); - Add<HDeoptimize>("Constant global variable assignment", - Deoptimizer::EAGER); + Add<HDeoptimize>(Deoptimizer::EAGER); builder.End(); } HInstruction* instr = @@ -5062,7 +5017,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { if (proxy != NULL) { Variable* var = proxy->var(); if (var->mode() == LET) { - return Bailout(kUnsupportedLetCompoundAssignment); + return Bailout("unsupported let compound assignment"); } CHECK_ALIVE(VisitForValue(operation)); @@ -5078,7 +5033,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { case Variable::PARAMETER: case Variable::LOCAL: if (var->mode() == CONST) { - return Bailout(kUnsupportedConstCompoundAssignment); + return Bailout("unsupported const compound assignment"); } BindIfLive(var, Top()); break; @@ -5094,7 +5049,8 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { int count = current_info()->scope()->num_parameters(); for (int i = 0; i < count; ++i) { if (var == current_info()->scope()->parameter(i)) { - Bailout(kAssignmentToParameterFunctionUsesArgumentsObject); + Bailout( + "assignment to parameter, function uses arguments object"); } } } @@ -5125,7 +5081,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { } case Variable::LOOKUP: - return Bailout(kCompoundAssignmentToLookupSlot); + return Bailout("compound assignment to lookup slot"); } return ast_context()->ReturnValue(Pop()); @@ -5173,7 +5129,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE); } - return BuildStoreNamed(expr, expr->id(), expr->position(), + return BuildStoreNamed(prop, expr->id(), expr->position(), expr->AssignmentId(), prop, object, instr, instr); } else { // Keyed property. @@ -5214,7 +5170,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { } } else { - return Bailout(kInvalidLhsInCompoundAssignment); + return Bailout("invalid lhs in compound assignment"); } } @@ -5251,11 +5207,11 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { } } else if (var->mode() == CONST_HARMONY) { if (expr->op() != Token::INIT_CONST_HARMONY) { - return Bailout(kNonInitializerAssignmentToConst); + return Bailout("non-initializer assignment to const"); } } - if (proxy->IsArguments()) return Bailout(kAssignmentToArguments); + if (proxy->IsArguments()) return Bailout("assignment to arguments"); // Handle the assignment. switch (var->location()) { @@ -5274,7 +5230,7 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { if (var->mode() == LET && expr->op() == Token::ASSIGN) { HValue* env_value = environment()->Lookup(var); if (env_value == graph()->GetConstantHole()) { - return Bailout(kAssignmentToLetVariableBeforeInitialization); + return Bailout("assignment to let variable before initialization"); } } // We do not allow the arguments object to occur in a context where it @@ -5296,7 +5252,7 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { int count = current_info()->scope()->num_parameters(); for (int i = 0; i < count; ++i) { if (var == current_info()->scope()->parameter(i)) { - return Bailout(kAssignmentToParameterInArgumentsObject); + return Bailout("assignment to parameter in arguments object"); } } } @@ -5337,10 +5293,10 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { } case Variable::LOOKUP: - return Bailout(kAssignmentToLOOKUPVariable); + return Bailout("assignment to LOOKUP variable"); } } else { - return Bailout(kInvalidLeftHandSideInAssignment); + return Bailout("invalid left-hand side in assignment"); } } @@ -5405,8 +5361,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( Handle<String> name, Property* expr) { if (expr->IsUninitialized()) { - Add<HDeoptimize>("Insufficient feedback for generic named load", - Deoptimizer::SOFT); + Add<HDeoptimize>(Deoptimizer::SOFT); } HValue* context = environment()->context(); return new(zone()) HLoadNamedGeneric(context, object, name); @@ -5463,7 +5418,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( Handle<JSObject> holder(lookup.holder()); Handle<Map> holder_map(holder->map()); HCheckMaps* type_check = AddCheckMap(object, map); - BuildCheckPrototypeMaps(prototype, holder); + Add<HCheckPrototypeMaps>(prototype, holder, top_info()); HValue* holder_value = Add<HConstant>(holder); return BuildLoadNamedField(holder_value, HObjectAccess::ForField(holder_map, &lookup, name), type_check); @@ -5475,7 +5430,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( Handle<JSObject> holder(lookup.holder()); Handle<Map> holder_map(holder->map()); AddCheckMap(object, map); - BuildCheckPrototypeMaps(prototype, holder); + Add<HCheckPrototypeMaps>(prototype, holder, top_info()); Handle<Object> constant(lookup.GetConstantFromMap(*holder_map), isolate()); return New<HConstant>(constant); } @@ -5511,7 +5466,7 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( isolate()->IsFastArrayConstructorPrototypeChainIntact()) { Handle<JSObject> prototype(JSObject::cast(map->prototype()), isolate()); Handle<JSObject> object_prototype = isolate()->initial_object_prototype(); - BuildCheckPrototypeMaps(prototype, object_prototype); + Add<HCheckPrototypeMaps>(prototype, object_prototype, top_info()); load_mode = ALLOW_RETURN_HOLE; graph()->MarkDependsOnEmptyArrayProtoElements(); } @@ -5724,8 +5679,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( // Deopt if none of the cases matched. NoObservableSideEffectsScope scope(this); - FinishExitWithHardDeoptimization("Unknown type in polymorphic element access", - join); + FinishExitWithHardDeoptimization(join); set_current_block(join); return is_store ? NULL : Pop(); } @@ -5761,14 +5715,12 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( } else { if (is_store) { if (expr->IsAssignment() && expr->AsAssignment()->IsUninitialized()) { - Add<HDeoptimize>("Insufficient feedback for keyed store", - Deoptimizer::SOFT); + Add<HDeoptimize>(Deoptimizer::SOFT); } instr = BuildStoreKeyedGeneric(obj, key, val); } else { if (expr->AsProperty()->IsUninitialized()) { - Add<HDeoptimize>("Insufficient feedback for keyed load", - Deoptimizer::SOFT); + Add<HDeoptimize>(Deoptimizer::SOFT); } instr = BuildLoadKeyedGeneric(obj, key); } @@ -5961,38 +5913,11 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) { } -void HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant, - CompilationInfo* info) { - HConstant* constant_value = New<HConstant>(constant); - - if (constant->map()->CanOmitMapChecks()) { - constant->map()->AddDependentCompilationInfo( - DependentCode::kPrototypeCheckGroup, info); - return; - } - - AddInstruction(constant_value); - HCheckMaps* check = - Add<HCheckMaps>(constant_value, handle(constant->map()), info); - check->ClearGVNFlag(kDependsOnElementsKind); -} - - -void HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype, - Handle<JSObject> holder) { - BuildConstantMapCheck(prototype, top_info()); - while (!prototype.is_identical_to(holder)) { - prototype = handle(JSObject::cast(prototype->GetPrototype())); - BuildConstantMapCheck(prototype, top_info()); - } -} - - void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, Handle<Map> receiver_map) { if (!holder.is_null()) { Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); - BuildCheckPrototypeMaps(prototype, holder); + Add<HCheckPrototypeMaps>(prototype, holder, top_info()); } } @@ -6215,7 +6140,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( // that the environment stack matches the depth on deopt that it otherwise // would have had after a successful call. Drop(argument_count - (ast_context()->IsEffect() ? 0 : 1)); - FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join); + FinishExitWithHardDeoptimization(join); } else { HValue* context = environment()->context(); HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count); @@ -6364,7 +6289,7 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind, if (target_info.isolate()->has_pending_exception()) { // Parse or scope error, never optimize this function. SetStackOverflow(); - target_shared->DisableOptimization(kParseScopeError); + target_shared->DisableOptimization("parse/scope error"); } TraceInline(target, caller, "parse failure"); return false; @@ -6503,7 +6428,7 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind, // Bail out if the inline function did, as we cannot residualize a call // instead. TraceInline(target, caller, "inline graph construction failed"); - target_shared->DisableOptimization(kInliningBailedOut); + target_shared->DisableOptimization("inlining bailed out"); inline_bailout_ = true; delete target_state; return true; @@ -6733,9 +6658,9 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( HValue* string = Pop(); HValue* context = environment()->context(); ASSERT(!expr->holder().is_null()); - BuildCheckPrototypeMaps(Call::GetPrototypeForPrimitiveCheck( + Add<HCheckPrototypeMaps>(Call::GetPrototypeForPrimitiveCheck( STRING_CHECK, expr->holder()->GetIsolate()), - expr->holder()); + expr->holder(), top_info()); HInstruction* char_code = BuildStringCharCodeAt(string, index); if (id == kStringCharCodeAt) { @@ -7048,7 +6973,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { } else { VariableProxy* proxy = expr->expression()->AsVariableProxy(); if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { - return Bailout(kPossibleDirectCallToEval); + return Bailout("possible direct call to eval"); } bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); @@ -7316,7 +7241,7 @@ void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) { ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); if (expr->is_jsruntime()) { - return Bailout(kCallToAJavaScriptRuntimeFunction); + return Bailout("call to a JavaScript runtime function"); } const Runtime::Function* function = expr->function(); @@ -7356,6 +7281,8 @@ void HOptimizedGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { case Token::DELETE: return VisitDelete(expr); case Token::VOID: return VisitVoid(expr); case Token::TYPEOF: return VisitTypeof(expr); + case Token::SUB: return VisitSub(expr); + case Token::BIT_NOT: return VisitBitNot(expr); case Token::NOT: return VisitNot(expr); default: UNREACHABLE(); } @@ -7381,7 +7308,7 @@ void HOptimizedGraphBuilder::VisitDelete(UnaryOperation* expr) { } else if (proxy != NULL) { Variable* var = proxy->var(); if (var->IsUnallocated()) { - Bailout(kDeleteWithGlobalVariable); + Bailout("delete with global variable"); } else if (var->IsStackAllocated() || var->IsContextSlot()) { // Result of deleting non-global variables is false. 'this' is not // really a variable, though we implement it as one. The @@ -7391,7 +7318,7 @@ void HOptimizedGraphBuilder::VisitDelete(UnaryOperation* expr) { : graph()->GetConstantFalse(); return ast_context()->ReturnValue(value); } else { - Bailout(kDeleteWithNonGlobalVariable); + Bailout("delete with non-global variable"); } } else { // Result of deleting non-property, non-variable reference is true. @@ -7417,6 +7344,24 @@ void HOptimizedGraphBuilder::VisitTypeof(UnaryOperation* expr) { } +void HOptimizedGraphBuilder::VisitSub(UnaryOperation* expr) { + CHECK_ALIVE(VisitForValue(expr->expression())); + Handle<Type> operand_type = expr->expression()->bounds().lower; + HValue* value = TruncateToNumber(Pop(), &operand_type); + HInstruction* instr = BuildUnaryMathOp(value, operand_type, Token::SUB); + return ast_context()->ReturnInstruction(instr, expr->id()); +} + + +void HOptimizedGraphBuilder::VisitBitNot(UnaryOperation* expr) { + CHECK_ALIVE(VisitForValue(expr->expression())); + Handle<Type> operand_type = expr->expression()->bounds().lower; + HValue* value = TruncateToNumber(Pop(), &operand_type); + HInstruction* instr = BuildUnaryMathOp(value, operand_type, Token::BIT_NOT); + return ast_context()->ReturnInstruction(instr, expr->id()); +} + + void HOptimizedGraphBuilder::VisitNot(UnaryOperation* expr) { if (ast_context()->IsTest()) { TestContext* context = TestContext::cast(ast_context()); @@ -7505,7 +7450,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { VariableProxy* proxy = target->AsVariableProxy(); Property* prop = target->AsProperty(); if (proxy == NULL && prop == NULL) { - return Bailout(kInvalidLhsInCountOperation); + return Bailout("invalid lhs in count operation"); } // Match the full code generator stack by simulating an extra stack @@ -7519,7 +7464,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { if (proxy != NULL) { Variable* var = proxy->var(); if (var->mode() == CONST) { - return Bailout(kUnsupportedCountOperationWithConst); + return Bailout("unsupported count operation with const"); } // Argument of the count operation is a variable, not a property. ASSERT(prop == NULL); @@ -7553,7 +7498,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { int count = current_info()->scope()->num_parameters(); for (int i = 0; i < count; ++i) { if (var == current_info()->scope()->parameter(i)) { - return Bailout(kAssignmentToParameterInArgumentsObject); + return Bailout("assignment to parameter in arguments object"); } } } @@ -7570,7 +7515,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { } case Variable::LOOKUP: - return Bailout(kLookupVariableInCountOperation); + return Bailout("lookup variable in count operation"); } } else { @@ -7613,7 +7558,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { after = BuildIncrement(returns_original_input, expr); HValue* result = returns_original_input ? Pop() : after; - return BuildStoreNamed(expr, expr->id(), expr->position(), + return BuildStoreNamed(prop, expr->id(), expr->position(), expr->AssignmentId(), prop, object, after, result); } else { // Keyed property. @@ -7775,14 +7720,12 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( } if (left_type->Is(Type::None())) { - Add<HDeoptimize>("Insufficient type feedback for left side", - Deoptimizer::SOFT); + Add<HDeoptimize>(Deoptimizer::SOFT); // TODO(rossberg): we should be able to get rid of non-continuous defaults. left_type = handle(Type::Any(), isolate()); } if (right_type->Is(Type::None())) { - Add<HDeoptimize>("Insufficient type feedback for right side", - Deoptimizer::SOFT); + Add<HDeoptimize>(Deoptimizer::SOFT); right_type = handle(Type::Any(), isolate()); } HInstruction* instr = NULL; @@ -8132,8 +8075,7 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { // Cases handled below depend on collected type feedback. They should // soft deoptimize when there is no type feedback. if (combined_type->Is(Type::None())) { - Add<HDeoptimize>("insufficient type feedback for combined type", - Deoptimizer::SOFT); + Add<HDeoptimize>(Deoptimizer::SOFT); combined_type = left_type = right_type = handle(Type::Any(), isolate()); } @@ -8162,7 +8104,7 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { } } default: - return Bailout(kUnsupportedNonPrimitiveCompare); + return Bailout("Unsupported non-primitive compare"); } } else if (combined_type->Is(Type::InternalizedString()) && Token::IsEqualityOp(op)) { @@ -8625,7 +8567,7 @@ void HOptimizedGraphBuilder::VisitVariableDeclaration( } break; case Variable::LOOKUP: - return Bailout(kUnsupportedLookupSlotInDeclaration); + return Bailout("unsupported lookup slot in declaration"); } } @@ -8663,7 +8605,7 @@ void HOptimizedGraphBuilder::VisitFunctionDeclaration( break; } case Variable::LOOKUP: - return Bailout(kUnsupportedLookupSlotInDeclaration); + return Bailout("unsupported lookup slot in declaration"); } } @@ -8784,7 +8726,7 @@ void HOptimizedGraphBuilder::GenerateIsObject(CallRuntime* call) { void HOptimizedGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) { - return Bailout(kInlinedRuntimeFunctionIsNonNegativeSmi); + return Bailout("inlined runtime function: IsNonNegativeSmi"); } @@ -8800,7 +8742,8 @@ void HOptimizedGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) { void HOptimizedGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( CallRuntime* call) { - return Bailout(kInlinedRuntimeFunctionIsStringWrapperSafeForDefaultValueOf); + return Bailout( + "inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); } @@ -8854,7 +8797,7 @@ void HOptimizedGraphBuilder::GenerateArguments(CallRuntime* call) { void HOptimizedGraphBuilder::GenerateClassOf(CallRuntime* call) { // The special form detected by IsClassOfTest is detected before we get here // and does not cause a bailout. - return Bailout(kInlinedRuntimeFunctionClassOf); + return Bailout("inlined runtime function: ClassOf"); } @@ -9071,7 +9014,7 @@ void HOptimizedGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) { // Support for fast native caches. void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) { - return Bailout(kInlinedRuntimeFunctionGetFromCache); + return Bailout("inlined runtime function: GetFromCache"); } @@ -9201,7 +9144,7 @@ void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) { // Check whether two RegExps are equivalent void HOptimizedGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) { - return Bailout(kInlinedRuntimeFunctionIsRegExpEquivalent); + return Bailout("inlined runtime function: IsRegExpEquivalent"); } @@ -9215,18 +9158,18 @@ void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) { void HOptimizedGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) { - return Bailout(kInlinedRuntimeFunctionFastAsciiArrayJoin); + return Bailout("inlined runtime function: FastAsciiArrayJoin"); } // Support for generators. void HOptimizedGraphBuilder::GenerateGeneratorNext(CallRuntime* call) { - return Bailout(kInlinedRuntimeFunctionGeneratorNext); + return Bailout("inlined runtime function: GeneratorNext"); } void HOptimizedGraphBuilder::GenerateGeneratorThrow(CallRuntime* call) { - return Bailout(kInlinedRuntimeFunctionGeneratorThrow); + return Bailout("inlined runtime function: GeneratorThrow"); } diff --git a/chromium/v8/src/hydrogen.h b/chromium/v8/src/hydrogen.h index 004aa16a878..20dc1a3e0ec 100644 --- a/chromium/v8/src/hydrogen.h +++ b/chromium/v8/src/hydrogen.h @@ -368,7 +368,7 @@ class HGraph: public ZoneObject { return NULL; } - bool Optimize(BailoutReason* bailout_reason); + bool Optimize(SmartArrayPointer<char>* bailout_reason); #ifdef DEBUG void Verify(bool do_full_verify) const; @@ -1266,8 +1266,7 @@ class HGraphBuilder { void PushAndAdd(HInstruction* instr); - void FinishExitWithHardDeoptimization(const char* reason, - HBasicBlock* continuation); + void FinishExitWithHardDeoptimization(HBasicBlock* continuation); void AddIncrementCounter(StatsCounter* counter, HValue* context); @@ -1371,10 +1370,10 @@ class HGraphBuilder { void Else(); void End(); - void Deopt(const char* reason); - void ElseDeopt(const char* reason) { + void Deopt(); + void ElseDeopt() { Else(); - Deopt(reason); + Deopt(); } void Return(HValue* value); @@ -1533,6 +1532,9 @@ class HGraphBuilder { ElementsKind kind, int length); + HInstruction* BuildUnaryMathOp( + HValue* value, Handle<Type> type, Token::Value token); + void BuildCompareNil( HValue* value, Handle<Type> type, @@ -1543,10 +1545,6 @@ class HGraphBuilder { int previous_object_size, HValue* payload); - void BuildConstantMapCheck(Handle<JSObject> constant, CompilationInfo* info); - void BuildCheckPrototypeMaps(Handle<JSObject> prototype, - Handle<JSObject> holder); - HInstruction* BuildGetNativeContext(); HInstruction* BuildGetArrayFunction(); @@ -1564,13 +1562,13 @@ class HGraphBuilder { template<> inline HInstruction* HGraphBuilder::AddUncasted<HDeoptimize>( - const char* reason, Deoptimizer::BailoutType type) { + Deoptimizer::BailoutType type) { if (type == Deoptimizer::SOFT) { isolate()->counters()->soft_deopts_requested()->Increment(); if (FLAG_always_opt) return NULL; } if (current_block()->IsDeoptimizing()) return NULL; - HDeoptimize* instr = New<HDeoptimize>(reason, type); + HDeoptimize* instr = New<HDeoptimize>(type); AddInstruction(instr); if (type == Deoptimizer::SOFT) { isolate()->counters()->soft_deopts_inserted()->Increment(); @@ -1583,8 +1581,8 @@ inline HInstruction* HGraphBuilder::AddUncasted<HDeoptimize>( template<> inline HDeoptimize* HGraphBuilder::Add<HDeoptimize>( - const char* reason, Deoptimizer::BailoutType type) { - return static_cast<HDeoptimize*>(AddUncasted<HDeoptimize>(reason, type)); + Deoptimizer::BailoutType type) { + return static_cast<HDeoptimize*>(AddUncasted<HDeoptimize>(type)); } @@ -1709,7 +1707,7 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor { HValue* context() { return environment()->context(); } - void Bailout(BailoutReason reason); + void Bailout(const char* reason); HBasicBlock* CreateJoin(HBasicBlock* first, HBasicBlock* second, @@ -1790,6 +1788,8 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor { void VisitDelete(UnaryOperation* expr); void VisitVoid(UnaryOperation* expr); void VisitTypeof(UnaryOperation* expr); + void VisitSub(UnaryOperation* expr); + void VisitBitNot(UnaryOperation* expr); void VisitNot(UnaryOperation* expr); void VisitComma(BinaryOperation* expr); diff --git a/chromium/v8/src/i18n.cc b/chromium/v8/src/i18n.cc deleted file mode 100644 index 5cfe4c43b2f..00000000000 --- a/chromium/v8/src/i18n.cc +++ /dev/null @@ -1,938 +0,0 @@ -// Copyright 2013 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. -// limitations under the License. - -#include "i18n.h" - -#include "unicode/calendar.h" -#include "unicode/coll.h" -#include "unicode/curramt.h" -#include "unicode/dcfmtsym.h" -#include "unicode/decimfmt.h" -#include "unicode/dtfmtsym.h" -#include "unicode/dtptngen.h" -#include "unicode/locid.h" -#include "unicode/numfmt.h" -#include "unicode/numsys.h" -#include "unicode/smpdtfmt.h" -#include "unicode/timezone.h" -#include "unicode/uchar.h" -#include "unicode/ucol.h" -#include "unicode/ucurr.h" -#include "unicode/unum.h" -#include "unicode/uversion.h" - -namespace v8 { -namespace internal { - -namespace { - -bool ExtractStringSetting(Isolate* isolate, - Handle<JSObject> options, - const char* key, - icu::UnicodeString* setting) { - Handle<String> str = isolate->factory()->NewStringFromAscii(CStrVector(key)); - MaybeObject* maybe_object = options->GetProperty(*str); - Object* object; - if (maybe_object->ToObject(&object) && object->IsString()) { - v8::String::Utf8Value utf8_string( - v8::Utils::ToLocal(Handle<String>(String::cast(object)))); - *setting = icu::UnicodeString::fromUTF8(*utf8_string); - return true; - } - return false; -} - - -bool ExtractIntegerSetting(Isolate* isolate, - Handle<JSObject> options, - const char* key, - int32_t* value) { - Handle<String> str = isolate->factory()->NewStringFromAscii(CStrVector(key)); - MaybeObject* maybe_object = options->GetProperty(*str); - Object* object; - if (maybe_object->ToObject(&object) && object->IsNumber()) { - object->ToInt32(value); - return true; - } - return false; -} - - -bool ExtractBooleanSetting(Isolate* isolate, - Handle<JSObject> options, - const char* key, - bool* value) { - Handle<String> str = isolate->factory()->NewStringFromAscii(CStrVector(key)); - MaybeObject* maybe_object = options->GetProperty(*str); - Object* object; - if (maybe_object->ToObject(&object) && object->IsBoolean()) { - *value = object->BooleanValue(); - return true; - } - return false; -} - - -icu::SimpleDateFormat* CreateICUDateFormat( - Isolate* isolate, - const icu::Locale& icu_locale, - Handle<JSObject> options) { - // Create time zone as specified by the user. We have to re-create time zone - // since calendar takes ownership. - icu::TimeZone* tz = NULL; - icu::UnicodeString timezone; - if (ExtractStringSetting(isolate, options, "timeZone", &timezone)) { - tz = icu::TimeZone::createTimeZone(timezone); - } else { - tz = icu::TimeZone::createDefault(); - } - - // Create a calendar using locale, and apply time zone to it. - UErrorCode status = U_ZERO_ERROR; - icu::Calendar* calendar = - icu::Calendar::createInstance(tz, icu_locale, status); - - // Make formatter from skeleton. Calendar and numbering system are added - // to the locale as Unicode extension (if they were specified at all). - icu::SimpleDateFormat* date_format = NULL; - icu::UnicodeString skeleton; - if (ExtractStringSetting(isolate, options, "skeleton", &skeleton)) { - icu::DateTimePatternGenerator* generator = - icu::DateTimePatternGenerator::createInstance(icu_locale, status); - icu::UnicodeString pattern; - if (U_SUCCESS(status)) { - pattern = generator->getBestPattern(skeleton, status); - delete generator; - } - - date_format = new icu::SimpleDateFormat(pattern, icu_locale, status); - if (U_SUCCESS(status)) { - date_format->adoptCalendar(calendar); - } - } - - if (U_FAILURE(status)) { - delete calendar; - delete date_format; - date_format = NULL; - } - - return date_format; -} - - -void SetResolvedDateSettings(Isolate* isolate, - const icu::Locale& icu_locale, - icu::SimpleDateFormat* date_format, - Handle<JSObject> resolved) { - UErrorCode status = U_ZERO_ERROR; - icu::UnicodeString pattern; - date_format->toPattern(pattern); - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("pattern")), - isolate->factory()->NewStringFromTwoByte( - Vector<const uint16_t>( - reinterpret_cast<const uint16_t*>(pattern.getBuffer()), - pattern.length())), - NONE, - kNonStrictMode); - - // Set time zone and calendar. - const icu::Calendar* calendar = date_format->getCalendar(); - const char* calendar_name = calendar->getType(); - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("calendar")), - isolate->factory()->NewStringFromAscii(CStrVector(calendar_name)), - NONE, - kNonStrictMode); - - const icu::TimeZone& tz = calendar->getTimeZone(); - icu::UnicodeString time_zone; - tz.getID(time_zone); - - icu::UnicodeString canonical_time_zone; - icu::TimeZone::getCanonicalID(time_zone, canonical_time_zone, status); - if (U_SUCCESS(status)) { - if (canonical_time_zone == UNICODE_STRING_SIMPLE("Etc/GMT")) { - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("timeZone")), - isolate->factory()->NewStringFromAscii(CStrVector("UTC")), - NONE, - kNonStrictMode); - } else { - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("timeZone")), - isolate->factory()->NewStringFromTwoByte( - Vector<const uint16_t>( - reinterpret_cast<const uint16_t*>( - canonical_time_zone.getBuffer()), - canonical_time_zone.length())), - NONE, - kNonStrictMode); - } - } - - // Ugly hack. ICU doesn't expose numbering system in any way, so we have - // to assume that for given locale NumberingSystem constructor produces the - // same digits as NumberFormat/Calendar would. - status = U_ZERO_ERROR; - icu::NumberingSystem* numbering_system = - icu::NumberingSystem::createInstance(icu_locale, status); - if (U_SUCCESS(status)) { - const char* ns = numbering_system->getName(); - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("numberingSystem")), - isolate->factory()->NewStringFromAscii(CStrVector(ns)), - NONE, - kNonStrictMode); - } else { - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("numberingSystem")), - isolate->factory()->undefined_value(), - NONE, - kNonStrictMode); - } - delete numbering_system; - - // Set the locale - char result[ULOC_FULLNAME_CAPACITY]; - status = U_ZERO_ERROR; - uloc_toLanguageTag( - icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status); - if (U_SUCCESS(status)) { - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("locale")), - isolate->factory()->NewStringFromAscii(CStrVector(result)), - NONE, - kNonStrictMode); - } else { - // This would never happen, since we got the locale from ICU. - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("locale")), - isolate->factory()->NewStringFromAscii(CStrVector("und")), - NONE, - kNonStrictMode); - } -} - - -template<int internal_fields, EternalHandles::SingletonHandle field> -Handle<ObjectTemplateInfo> GetEternal(Isolate* isolate) { - if (isolate->eternal_handles()->Exists(field)) { - return Handle<ObjectTemplateInfo>::cast( - isolate->eternal_handles()->GetSingleton(field)); - } - v8::Local<v8::ObjectTemplate> raw_template(v8::ObjectTemplate::New()); - raw_template->SetInternalFieldCount(internal_fields); - return Handle<ObjectTemplateInfo>::cast( - isolate->eternal_handles()->CreateSingleton( - isolate, - *v8::Utils::OpenHandle(*raw_template), - field)); -} - - -icu::DecimalFormat* CreateICUNumberFormat( - Isolate* isolate, - const icu::Locale& icu_locale, - Handle<JSObject> options) { - // Make formatter from options. Numbering system is added - // to the locale as Unicode extension (if it was specified at all). - UErrorCode status = U_ZERO_ERROR; - icu::DecimalFormat* number_format = NULL; - icu::UnicodeString style; - icu::UnicodeString currency; - if (ExtractStringSetting(isolate, options, "style", &style)) { - if (style == UNICODE_STRING_SIMPLE("currency")) { - icu::UnicodeString display; - ExtractStringSetting(isolate, options, "currency", ¤cy); - ExtractStringSetting(isolate, options, "currencyDisplay", &display); - -#if (U_ICU_VERSION_MAJOR_NUM == 4) && (U_ICU_VERSION_MINOR_NUM <= 6) - icu::NumberFormat::EStyles format_style; - if (display == UNICODE_STRING_SIMPLE("code")) { - format_style = icu::NumberFormat::kIsoCurrencyStyle; - } else if (display == UNICODE_STRING_SIMPLE("name")) { - format_style = icu::NumberFormat::kPluralCurrencyStyle; - } else { - format_style = icu::NumberFormat::kCurrencyStyle; - } -#else // ICU version is 4.8 or above (we ignore versions below 4.0). - UNumberFormatStyle format_style; - if (display == UNICODE_STRING_SIMPLE("code")) { - format_style = UNUM_CURRENCY_ISO; - } else if (display == UNICODE_STRING_SIMPLE("name")) { - format_style = UNUM_CURRENCY_PLURAL; - } else { - format_style = UNUM_CURRENCY; - } -#endif - - number_format = static_cast<icu::DecimalFormat*>( - icu::NumberFormat::createInstance(icu_locale, format_style, status)); - } else if (style == UNICODE_STRING_SIMPLE("percent")) { - number_format = static_cast<icu::DecimalFormat*>( - icu::NumberFormat::createPercentInstance(icu_locale, status)); - if (U_FAILURE(status)) { - delete number_format; - return NULL; - } - // Make sure 1.1% doesn't go into 2%. - number_format->setMinimumFractionDigits(1); - } else { - // Make a decimal instance by default. - number_format = static_cast<icu::DecimalFormat*>( - icu::NumberFormat::createInstance(icu_locale, status)); - } - } - - if (U_FAILURE(status)) { - delete number_format; - return NULL; - } - - // Set all options. - if (!currency.isEmpty()) { - number_format->setCurrency(currency.getBuffer(), status); - } - - int32_t digits; - if (ExtractIntegerSetting( - isolate, options, "minimumIntegerDigits", &digits)) { - number_format->setMinimumIntegerDigits(digits); - } - - if (ExtractIntegerSetting( - isolate, options, "minimumFractionDigits", &digits)) { - number_format->setMinimumFractionDigits(digits); - } - - if (ExtractIntegerSetting( - isolate, options, "maximumFractionDigits", &digits)) { - number_format->setMaximumFractionDigits(digits); - } - - bool significant_digits_used = false; - if (ExtractIntegerSetting( - isolate, options, "minimumSignificantDigits", &digits)) { - number_format->setMinimumSignificantDigits(digits); - significant_digits_used = true; - } - - if (ExtractIntegerSetting( - isolate, options, "maximumSignificantDigits", &digits)) { - number_format->setMaximumSignificantDigits(digits); - significant_digits_used = true; - } - - number_format->setSignificantDigitsUsed(significant_digits_used); - - bool grouping; - if (ExtractBooleanSetting(isolate, options, "useGrouping", &grouping)) { - number_format->setGroupingUsed(grouping); - } - - // Set rounding mode. - number_format->setRoundingMode(icu::DecimalFormat::kRoundHalfUp); - - return number_format; -} - - -void SetResolvedNumberSettings(Isolate* isolate, - const icu::Locale& icu_locale, - icu::DecimalFormat* number_format, - Handle<JSObject> resolved) { - icu::UnicodeString pattern; - number_format->toPattern(pattern); - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("pattern")), - isolate->factory()->NewStringFromTwoByte( - Vector<const uint16_t>( - reinterpret_cast<const uint16_t*>(pattern.getBuffer()), - pattern.length())), - NONE, - kNonStrictMode); - - // Set resolved currency code in options.currency if not empty. - icu::UnicodeString currency(number_format->getCurrency()); - if (!currency.isEmpty()) { - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("currency")), - isolate->factory()->NewStringFromTwoByte( - Vector<const uint16_t>( - reinterpret_cast<const uint16_t*>(currency.getBuffer()), - currency.length())), - NONE, - kNonStrictMode); - } - - // Ugly hack. ICU doesn't expose numbering system in any way, so we have - // to assume that for given locale NumberingSystem constructor produces the - // same digits as NumberFormat/Calendar would. - UErrorCode status = U_ZERO_ERROR; - icu::NumberingSystem* numbering_system = - icu::NumberingSystem::createInstance(icu_locale, status); - if (U_SUCCESS(status)) { - const char* ns = numbering_system->getName(); - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("numberingSystem")), - isolate->factory()->NewStringFromAscii(CStrVector(ns)), - NONE, - kNonStrictMode); - } else { - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("numberingSystem")), - isolate->factory()->undefined_value(), - NONE, - kNonStrictMode); - } - delete numbering_system; - - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("useGrouping")), - isolate->factory()->ToBoolean(number_format->isGroupingUsed()), - NONE, - kNonStrictMode); - - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii( - CStrVector("minimumIntegerDigits")), - isolate->factory()->NewNumberFromInt( - number_format->getMinimumIntegerDigits()), - NONE, - kNonStrictMode); - - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii( - CStrVector("minimumFractionDigits")), - isolate->factory()->NewNumberFromInt( - number_format->getMinimumFractionDigits()), - NONE, - kNonStrictMode); - - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii( - CStrVector("maximumFractionDigits")), - isolate->factory()->NewNumberFromInt( - number_format->getMaximumFractionDigits()), - NONE, - kNonStrictMode); - - Handle<String> key = isolate->factory()->NewStringFromAscii( - CStrVector("minimumSignificantDigits")); - if (resolved->HasLocalProperty(*key)) { - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii( - CStrVector("minimumSignificantDigits")), - isolate->factory()->NewNumberFromInt( - number_format->getMinimumSignificantDigits()), - NONE, - kNonStrictMode); - } - - key = isolate->factory()->NewStringFromAscii( - CStrVector("maximumSignificantDigits")); - if (resolved->HasLocalProperty(*key)) { - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii( - CStrVector("maximumSignificantDigits")), - isolate->factory()->NewNumberFromInt( - number_format->getMaximumSignificantDigits()), - NONE, - kNonStrictMode); - } - - // Set the locale - char result[ULOC_FULLNAME_CAPACITY]; - status = U_ZERO_ERROR; - uloc_toLanguageTag( - icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status); - if (U_SUCCESS(status)) { - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("locale")), - isolate->factory()->NewStringFromAscii(CStrVector(result)), - NONE, - kNonStrictMode); - } else { - // This would never happen, since we got the locale from ICU. - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("locale")), - isolate->factory()->NewStringFromAscii(CStrVector("und")), - NONE, - kNonStrictMode); - } -} - - -icu::Collator* CreateICUCollator( - Isolate* isolate, - const icu::Locale& icu_locale, - Handle<JSObject> options) { - // Make collator from options. - icu::Collator* collator = NULL; - UErrorCode status = U_ZERO_ERROR; - collator = icu::Collator::createInstance(icu_locale, status); - - if (U_FAILURE(status)) { - delete collator; - return NULL; - } - - // Set flags first, and then override them with sensitivity if necessary. - bool numeric; - if (ExtractBooleanSetting(isolate, options, "numeric", &numeric)) { - collator->setAttribute( - UCOL_NUMERIC_COLLATION, numeric ? UCOL_ON : UCOL_OFF, status); - } - - // Normalization is always on, by the spec. We are free to optimize - // if the strings are already normalized (but we don't have a way to tell - // that right now). - collator->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status); - - icu::UnicodeString case_first; - if (ExtractStringSetting(isolate, options, "caseFirst", &case_first)) { - if (case_first == UNICODE_STRING_SIMPLE("upper")) { - collator->setAttribute(UCOL_CASE_FIRST, UCOL_UPPER_FIRST, status); - } else if (case_first == UNICODE_STRING_SIMPLE("lower")) { - collator->setAttribute(UCOL_CASE_FIRST, UCOL_LOWER_FIRST, status); - } else { - // Default (false/off). - collator->setAttribute(UCOL_CASE_FIRST, UCOL_OFF, status); - } - } - - icu::UnicodeString sensitivity; - if (ExtractStringSetting(isolate, options, "sensitivity", &sensitivity)) { - if (sensitivity == UNICODE_STRING_SIMPLE("base")) { - collator->setStrength(icu::Collator::PRIMARY); - } else if (sensitivity == UNICODE_STRING_SIMPLE("accent")) { - collator->setStrength(icu::Collator::SECONDARY); - } else if (sensitivity == UNICODE_STRING_SIMPLE("case")) { - collator->setStrength(icu::Collator::PRIMARY); - collator->setAttribute(UCOL_CASE_LEVEL, UCOL_ON, status); - } else { - // variant (default) - collator->setStrength(icu::Collator::TERTIARY); - } - } - - bool ignore; - if (ExtractBooleanSetting(isolate, options, "ignorePunctuation", &ignore)) { - if (ignore) { - collator->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, status); - } - } - - return collator; -} - - -void SetResolvedCollatorSettings(Isolate* isolate, - const icu::Locale& icu_locale, - icu::Collator* collator, - Handle<JSObject> resolved) { - UErrorCode status = U_ZERO_ERROR; - - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("numeric")), - isolate->factory()->ToBoolean( - collator->getAttribute(UCOL_NUMERIC_COLLATION, status) == UCOL_ON), - NONE, - kNonStrictMode); - - switch (collator->getAttribute(UCOL_CASE_FIRST, status)) { - case UCOL_LOWER_FIRST: - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("caseFirst")), - isolate->factory()->NewStringFromAscii(CStrVector("lower")), - NONE, - kNonStrictMode); - break; - case UCOL_UPPER_FIRST: - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("caseFirst")), - isolate->factory()->NewStringFromAscii(CStrVector("upper")), - NONE, - kNonStrictMode); - break; - default: - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("caseFirst")), - isolate->factory()->NewStringFromAscii(CStrVector("false")), - NONE, - kNonStrictMode); - } - - switch (collator->getAttribute(UCOL_STRENGTH, status)) { - case UCOL_PRIMARY: { - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("strength")), - isolate->factory()->NewStringFromAscii(CStrVector("primary")), - NONE, - kNonStrictMode); - - // case level: true + s1 -> case, s1 -> base. - if (UCOL_ON == collator->getAttribute(UCOL_CASE_LEVEL, status)) { - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("sensitivity")), - isolate->factory()->NewStringFromAscii(CStrVector("case")), - NONE, - kNonStrictMode); - } else { - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("sensitivity")), - isolate->factory()->NewStringFromAscii(CStrVector("base")), - NONE, - kNonStrictMode); - } - break; - } - case UCOL_SECONDARY: - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("strength")), - isolate->factory()->NewStringFromAscii(CStrVector("secondary")), - NONE, - kNonStrictMode); - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("sensitivity")), - isolate->factory()->NewStringFromAscii(CStrVector("accent")), - NONE, - kNonStrictMode); - break; - case UCOL_TERTIARY: - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("strength")), - isolate->factory()->NewStringFromAscii(CStrVector("tertiary")), - NONE, - kNonStrictMode); - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("sensitivity")), - isolate->factory()->NewStringFromAscii(CStrVector("variant")), - NONE, - kNonStrictMode); - break; - case UCOL_QUATERNARY: - // We shouldn't get quaternary and identical from ICU, but if we do - // put them into variant. - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("strength")), - isolate->factory()->NewStringFromAscii(CStrVector("quaternary")), - NONE, - kNonStrictMode); - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("sensitivity")), - isolate->factory()->NewStringFromAscii(CStrVector("variant")), - NONE, - kNonStrictMode); - break; - default: - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("strength")), - isolate->factory()->NewStringFromAscii(CStrVector("identical")), - NONE, - kNonStrictMode); - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("sensitivity")), - isolate->factory()->NewStringFromAscii(CStrVector("variant")), - NONE, - kNonStrictMode); - } - - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("ignorePunctuation")), - isolate->factory()->ToBoolean(collator->getAttribute( - UCOL_ALTERNATE_HANDLING, status) == UCOL_SHIFTED), - NONE, - kNonStrictMode); - - // Set the locale - char result[ULOC_FULLNAME_CAPACITY]; - status = U_ZERO_ERROR; - uloc_toLanguageTag( - icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status); - if (U_SUCCESS(status)) { - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("locale")), - isolate->factory()->NewStringFromAscii(CStrVector(result)), - NONE, - kNonStrictMode); - } else { - // This would never happen, since we got the locale from ICU. - JSObject::SetProperty( - resolved, - isolate->factory()->NewStringFromAscii(CStrVector("locale")), - isolate->factory()->NewStringFromAscii(CStrVector("und")), - NONE, - kNonStrictMode); - } -} - -} // namespace - - -// static -Handle<ObjectTemplateInfo> I18N::GetTemplate(Isolate* isolate) { - return GetEternal<1, i::EternalHandles::I18N_TEMPLATE_ONE>(isolate); -} - - -// static -Handle<ObjectTemplateInfo> I18N::GetTemplate2(Isolate* isolate) { - return GetEternal<2, i::EternalHandles::I18N_TEMPLATE_TWO>(isolate); -} - - -// static -icu::SimpleDateFormat* DateFormat::InitializeDateTimeFormat( - Isolate* isolate, - Handle<String> locale, - Handle<JSObject> options, - Handle<JSObject> resolved) { - // Convert BCP47 into ICU locale format. - UErrorCode status = U_ZERO_ERROR; - icu::Locale icu_locale; - char icu_result[ULOC_FULLNAME_CAPACITY]; - int icu_length = 0; - v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale)); - if (bcp47_locale.length() != 0) { - uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY, - &icu_length, &status); - if (U_FAILURE(status) || icu_length == 0) { - return NULL; - } - icu_locale = icu::Locale(icu_result); - } - - icu::SimpleDateFormat* date_format = CreateICUDateFormat( - isolate, icu_locale, options); - if (!date_format) { - // Remove extensions and try again. - icu::Locale no_extension_locale(icu_locale.getBaseName()); - date_format = CreateICUDateFormat(isolate, no_extension_locale, options); - - // Set resolved settings (pattern, numbering system, calendar). - SetResolvedDateSettings( - isolate, no_extension_locale, date_format, resolved); - } else { - SetResolvedDateSettings(isolate, icu_locale, date_format, resolved); - } - - return date_format; -} - - -icu::SimpleDateFormat* DateFormat::UnpackDateFormat( - Isolate* isolate, - Handle<JSObject> obj) { - Handle<String> key = - isolate->factory()->NewStringFromAscii(CStrVector("dateFormat")); - if (obj->HasLocalProperty(*key)) { - return reinterpret_cast<icu::SimpleDateFormat*>( - obj->GetInternalField(0)); - } - - return NULL; -} - - -void DateFormat::DeleteDateFormat(v8::Isolate* isolate, - Persistent<v8::Object>* object, - void* param) { - // First delete the hidden C++ object. - delete reinterpret_cast<icu::SimpleDateFormat*>(Handle<JSObject>::cast( - v8::Utils::OpenPersistent(object))->GetInternalField(0)); - - // Then dispose of the persistent handle to JS object. - object->Dispose(isolate); -} - - -icu::DecimalFormat* NumberFormat::InitializeNumberFormat( - Isolate* isolate, - Handle<String> locale, - Handle<JSObject> options, - Handle<JSObject> resolved) { - // Convert BCP47 into ICU locale format. - UErrorCode status = U_ZERO_ERROR; - icu::Locale icu_locale; - char icu_result[ULOC_FULLNAME_CAPACITY]; - int icu_length = 0; - v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale)); - if (bcp47_locale.length() != 0) { - uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY, - &icu_length, &status); - if (U_FAILURE(status) || icu_length == 0) { - return NULL; - } - icu_locale = icu::Locale(icu_result); - } - - icu::DecimalFormat* number_format = - CreateICUNumberFormat(isolate, icu_locale, options); - if (!number_format) { - // Remove extensions and try again. - icu::Locale no_extension_locale(icu_locale.getBaseName()); - number_format = CreateICUNumberFormat( - isolate, no_extension_locale, options); - - // Set resolved settings (pattern, numbering system). - SetResolvedNumberSettings( - isolate, no_extension_locale, number_format, resolved); - } else { - SetResolvedNumberSettings(isolate, icu_locale, number_format, resolved); - } - - return number_format; -} - - -icu::DecimalFormat* NumberFormat::UnpackNumberFormat( - Isolate* isolate, - Handle<JSObject> obj) { - Handle<String> key = - isolate->factory()->NewStringFromAscii(CStrVector("numberFormat")); - if (obj->HasLocalProperty(*key)) { - return reinterpret_cast<icu::DecimalFormat*>(obj->GetInternalField(0)); - } - - return NULL; -} - - -void NumberFormat::DeleteNumberFormat(v8::Isolate* isolate, - Persistent<v8::Object>* object, - void* param) { - // First delete the hidden C++ object. - delete reinterpret_cast<icu::DecimalFormat*>(Handle<JSObject>::cast( - v8::Utils::OpenPersistent(object))->GetInternalField(0)); - - // Then dispose of the persistent handle to JS object. - object->Dispose(isolate); -} - - -icu::Collator* Collator::InitializeCollator( - Isolate* isolate, - Handle<String> locale, - Handle<JSObject> options, - Handle<JSObject> resolved) { - // Convert BCP47 into ICU locale format. - UErrorCode status = U_ZERO_ERROR; - icu::Locale icu_locale; - char icu_result[ULOC_FULLNAME_CAPACITY]; - int icu_length = 0; - v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale)); - if (bcp47_locale.length() != 0) { - uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY, - &icu_length, &status); - if (U_FAILURE(status) || icu_length == 0) { - return NULL; - } - icu_locale = icu::Locale(icu_result); - } - - icu::Collator* collator = CreateICUCollator(isolate, icu_locale, options); - if (!collator) { - // Remove extensions and try again. - icu::Locale no_extension_locale(icu_locale.getBaseName()); - collator = CreateICUCollator(isolate, no_extension_locale, options); - - // Set resolved settings (pattern, numbering system). - SetResolvedCollatorSettings( - isolate, no_extension_locale, collator, resolved); - } else { - SetResolvedCollatorSettings(isolate, icu_locale, collator, resolved); - } - - return collator; -} - - -icu::Collator* Collator::UnpackCollator(Isolate* isolate, - Handle<JSObject> obj) { - Handle<String> key = - isolate->factory()->NewStringFromAscii(CStrVector("collator")); - if (obj->HasLocalProperty(*key)) { - return reinterpret_cast<icu::Collator*>(obj->GetInternalField(0)); - } - - return NULL; -} - - -void Collator::DeleteCollator(v8::Isolate* isolate, - Persistent<v8::Object>* object, - void* param) { - // First delete the hidden C++ object. - delete reinterpret_cast<icu::Collator*>(Handle<JSObject>::cast( - v8::Utils::OpenPersistent(object))->GetInternalField(0)); - - // Then dispose of the persistent handle to JS object. - object->Dispose(isolate); -} - -} } // namespace v8::internal diff --git a/chromium/v8/src/i18n.h b/chromium/v8/src/i18n.h deleted file mode 100644 index 5825ab6c6c7..00000000000 --- a/chromium/v8/src/i18n.h +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2013 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. -// limitations under the License. - -#ifndef V8_I18N_H_ -#define V8_I18N_H_ - -#include "unicode/uversion.h" -#include "v8.h" - -namespace U_ICU_NAMESPACE { -class Collator; -class DecimalFormat; -class SimpleDateFormat; -} - -namespace v8 { -namespace internal { - -class I18N { - public: - // Creates an ObjectTemplate with one internal field. - static Handle<ObjectTemplateInfo> GetTemplate(Isolate* isolate); - - // Creates an ObjectTemplate with two internal fields. - static Handle<ObjectTemplateInfo> GetTemplate2(Isolate* isolate); - - private: - I18N(); -}; - - -class DateFormat { - public: - // Create a formatter for the specificied locale and options. Returns the - // resolved settings for the locale / options. - static icu::SimpleDateFormat* InitializeDateTimeFormat( - Isolate* isolate, - Handle<String> locale, - Handle<JSObject> options, - Handle<JSObject> resolved); - - // Unpacks date format object from corresponding JavaScript object. - static icu::SimpleDateFormat* UnpackDateFormat(Isolate* isolate, - Handle<JSObject> obj); - - // Release memory we allocated for the DateFormat once the JS object that - // holds the pointer gets garbage collected. - static void DeleteDateFormat(v8::Isolate* isolate, - Persistent<v8::Object>* object, - void* param); - private: - DateFormat(); -}; - - -class NumberFormat { - public: - // Create a formatter for the specificied locale and options. Returns the - // resolved settings for the locale / options. - static icu::DecimalFormat* InitializeNumberFormat( - Isolate* isolate, - Handle<String> locale, - Handle<JSObject> options, - Handle<JSObject> resolved); - - // Unpacks number format object from corresponding JavaScript object. - static icu::DecimalFormat* UnpackNumberFormat(Isolate* isolate, - Handle<JSObject> obj); - - // Release memory we allocated for the NumberFormat once the JS object that - // holds the pointer gets garbage collected. - static void DeleteNumberFormat(v8::Isolate* isolate, - Persistent<v8::Object>* object, - void* param); - private: - NumberFormat(); -}; - - -class Collator { - public: - // Create a collator for the specificied locale and options. Returns the - // resolved settings for the locale / options. - static icu::Collator* InitializeCollator( - Isolate* isolate, - Handle<String> locale, - Handle<JSObject> options, - Handle<JSObject> resolved); - - // Unpacks collator object from corresponding JavaScript object. - static icu::Collator* UnpackCollator(Isolate* isolate, Handle<JSObject> obj); - - // Release memory we allocated for the Collator once the JS object that holds - // the pointer gets garbage collected. - static void DeleteCollator(v8::Isolate* isolate, - Persistent<v8::Object>* object, - void* param); - private: - Collator(); -}; - -} } // namespace v8::internal - -#endif // V8_I18N_H_ diff --git a/chromium/v8/src/ia32/assembler-ia32.cc b/chromium/v8/src/ia32/assembler-ia32.cc index 7bea3730258..e0ae0066552 100644 --- a/chromium/v8/src/ia32/assembler-ia32.cc +++ b/chromium/v8/src/ia32/assembler-ia32.cc @@ -1227,10 +1227,6 @@ void Assembler::test_b(Register reg, const Operand& op) { void Assembler::test(const Operand& op, const Immediate& imm) { - if (op.is_reg_only()) { - test(op.reg(), imm); - return; - } EnsureSpace ensure_space(this); EMIT(0xF7); emit_operand(eax, op); diff --git a/chromium/v8/src/ia32/builtins-ia32.cc b/chromium/v8/src/ia32/builtins-ia32.cc index 59124eab757..b90a17f6c38 100644 --- a/chromium/v8/src/ia32/builtins-ia32.cc +++ b/chromium/v8/src/ia32/builtins-ia32.cc @@ -241,7 +241,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, if (FLAG_debug_code) { __ cmp(esi, edi); __ Assert(less_equal, - kUnexpectedNumberOfPreAllocatedPropertyFields); + "Unexpected number of pre-allocated property fields."); } __ InitializeFieldsWithFiller(ecx, esi, edx); __ mov(edx, factory->one_pointer_filler_map()); @@ -272,7 +272,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, __ sub(edx, ecx); // Done if no extra properties are to be allocated. __ j(zero, &allocated); - __ Assert(positive, kPropertyAllocationCountFailed); + __ Assert(positive, "Property allocation count failed."); // Scale the number of elements by pointer size and add the header for // FixedArrays to the start of the next object calculation from above. @@ -654,7 +654,7 @@ static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm, __ ret(2 * kPointerSize); // Remove state, eax. __ bind(¬_tos_eax); - __ Abort(kNoCasesLeft); + __ Abort("no cases left"); } @@ -1033,9 +1033,9 @@ void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); // Will both indicate a NULL and a Smi. __ test(ebx, Immediate(kSmiTagMask)); - __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction); + __ Assert(not_zero, "Unexpected initial map for InternalArray function"); __ CmpObjectType(ebx, MAP_TYPE, ecx); - __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction); + __ Assert(equal, "Unexpected initial map for InternalArray function"); } // Run the native code for the InternalArray function called as a normal @@ -1062,9 +1062,9 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); // Will both indicate a NULL and a Smi. __ test(ebx, Immediate(kSmiTagMask)); - __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction); + __ Assert(not_zero, "Unexpected initial map for Array function"); __ CmpObjectType(ebx, MAP_TYPE, ecx); - __ Assert(equal, kUnexpectedInitialMapForArrayFunction); + __ Assert(equal, "Unexpected initial map for Array function"); } // Run the native code for the Array function called as a normal function. @@ -1092,7 +1092,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { if (FLAG_debug_code) { __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx); __ cmp(edi, ecx); - __ Assert(equal, kUnexpectedStringFunction); + __ Assert(equal, "Unexpected String function"); } // Load the first argument into eax and get rid of the rest @@ -1137,9 +1137,9 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { if (FLAG_debug_code) { __ cmpb(FieldOperand(ecx, Map::kInstanceSizeOffset), JSValue::kSize >> kPointerSizeLog2); - __ Assert(equal, kUnexpectedStringWrapperInstanceSize); + __ Assert(equal, "Unexpected string wrapper instance size"); __ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0); - __ Assert(equal, kUnexpectedUnusedPropertiesOfStringWrapper); + __ Assert(equal, "Unexpected unused properties of string wrapper"); } __ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx); diff --git a/chromium/v8/src/ia32/code-stubs-ia32.cc b/chromium/v8/src/ia32/code-stubs-ia32.cc index 12cc499a777..5789f49216f 100644 --- a/chromium/v8/src/ia32/code-stubs-ia32.cc +++ b/chromium/v8/src/ia32/code-stubs-ia32.cc @@ -250,6 +250,17 @@ void ToBooleanStub::InitializeInterfaceDescriptor( } +void UnaryOpStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + static Register registers[] = { eax }; + descriptor->register_param_count_ = 1; + descriptor->register_params_ = registers; + descriptor->deoptimization_handler_ = + FUNCTION_ADDR(UnaryOpIC_Miss); +} + + void StoreGlobalStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { @@ -500,8 +511,9 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) { Label after_sentinel; __ JumpIfNotSmi(ecx, &after_sentinel, Label::kNear); if (FLAG_debug_code) { + const char* message = "Expected 0 as a Smi sentinel"; __ cmp(ecx, 0); - __ Assert(equal, kExpected0AsASmiSentinel); + __ Assert(equal, message); } __ mov(ecx, GlobalObjectOperand()); __ mov(ecx, FieldOperand(ecx, GlobalObject::kNativeContextOffset)); @@ -3457,9 +3469,9 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); if (FLAG_debug_code) { __ test(ecx, Immediate(kSmiTagMask)); - __ Check(not_zero, kUnexpectedTypeForRegExpDataFixedArrayExpected); + __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected"); __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx); - __ Check(equal, kUnexpectedTypeForRegExpDataFixedArrayExpected); + __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); } // ecx: RegExp data (FixedArray) @@ -3819,7 +3831,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // Assert that we do not have a cons or slice (indirect strings) here. // Sequential strings have already been ruled out. __ test_b(ebx, kIsIndirectStringMask); - __ Assert(zero, kExternalStringExpectedButNotFound); + __ Assert(zero, "external string expected, but not found"); } __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset)); // Move the pointer so that offset-wise, it looks like a sequential string. @@ -3956,7 +3968,11 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm, Register scratch = scratch2; // Load the number string cache. - __ LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex); + ExternalReference roots_array_start = + ExternalReference::roots_array_start(masm->isolate()); + __ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex)); + __ mov(number_string_cache, + Operand::StaticArray(scratch, times_pointer_size, roots_array_start)); // Make the hash mask from the length of the number string cache. It // contains two elements (number and string) for each cache entry. __ mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset)); @@ -4310,7 +4326,7 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { edi); } #ifdef DEBUG - __ Abort(kUnexpectedFallThroughFromStringComparison); + __ Abort("Unexpected fall-through from string comparison"); #endif __ bind(&check_unequal_objects); @@ -5006,6 +5022,9 @@ void InstanceofStub::Generate(MacroAssembler* masm) { static const int8_t kCmpEdiOperandByte2 = BitCast<int8_t, uint8_t>(0x3d); static const int8_t kMovEaxImmediateByte = BitCast<int8_t, uint8_t>(0xb8); + ExternalReference roots_array_start = + ExternalReference::roots_array_start(masm->isolate()); + ASSERT_EQ(object.code(), InstanceofStub::left().code()); ASSERT_EQ(function.code(), InstanceofStub::right().code()); @@ -5025,11 +5044,18 @@ void InstanceofStub::Generate(MacroAssembler* masm) { if (!HasCallSiteInlineCheck()) { // Look up the function and the map in the instanceof cache. Label miss; - __ CompareRoot(function, scratch, Heap::kInstanceofCacheFunctionRootIndex); + __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); + __ cmp(function, Operand::StaticArray(scratch, + times_pointer_size, + roots_array_start)); __ j(not_equal, &miss, Label::kNear); - __ CompareRoot(map, scratch, Heap::kInstanceofCacheMapRootIndex); + __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); + __ cmp(map, Operand::StaticArray( + scratch, times_pointer_size, roots_array_start)); __ j(not_equal, &miss, Label::kNear); - __ LoadRoot(eax, Heap::kInstanceofCacheAnswerRootIndex); + __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); + __ mov(eax, Operand::StaticArray( + scratch, times_pointer_size, roots_array_start)); __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); __ bind(&miss); } @@ -5044,8 +5070,12 @@ void InstanceofStub::Generate(MacroAssembler* masm) { // Update the global instanceof or call site inlined cache with the current // map and function. The cached answer will be set when it is known below. if (!HasCallSiteInlineCheck()) { - __ StoreRoot(map, scratch, Heap::kInstanceofCacheMapRootIndex); - __ StoreRoot(function, scratch, Heap::kInstanceofCacheFunctionRootIndex); + __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); + __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start), + map); + __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); + __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start), + function); } else { // The constants for the code patching are based on no push instructions // at the call site. @@ -5055,9 +5085,9 @@ void InstanceofStub::Generate(MacroAssembler* masm) { __ sub(scratch, Operand(esp, 1 * kPointerSize)); if (FLAG_debug_code) { __ cmpb(Operand(scratch, 0), kCmpEdiOperandByte1); - __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheCmp1); + __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 1)"); __ cmpb(Operand(scratch, 1), kCmpEdiOperandByte2); - __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheCmp2); + __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 2)"); } __ mov(scratch, Operand(scratch, kDeltaToCmpImmediate)); __ mov(Operand(scratch, 0), map); @@ -5079,8 +5109,10 @@ void InstanceofStub::Generate(MacroAssembler* masm) { __ bind(&is_instance); if (!HasCallSiteInlineCheck()) { - __ mov(eax, Immediate(0)); - __ StoreRoot(eax, scratch, Heap::kInstanceofCacheAnswerRootIndex); + __ Set(eax, Immediate(0)); + __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); + __ mov(Operand::StaticArray(scratch, + times_pointer_size, roots_array_start), eax); } else { // Get return address and delta to inlined map check. __ mov(eax, factory->true_value()); @@ -5088,7 +5120,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) { __ sub(scratch, Operand(esp, 1 * kPointerSize)); if (FLAG_debug_code) { __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); - __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov); + __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); } __ mov(Operand(scratch, kDeltaToMovImmediate), eax); if (!ReturnTrueFalseObject()) { @@ -5099,8 +5131,10 @@ void InstanceofStub::Generate(MacroAssembler* masm) { __ bind(&is_not_instance); if (!HasCallSiteInlineCheck()) { - __ mov(eax, Immediate(Smi::FromInt(1))); - __ StoreRoot(eax, scratch, Heap::kInstanceofCacheAnswerRootIndex); + __ Set(eax, Immediate(Smi::FromInt(1))); + __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); + __ mov(Operand::StaticArray( + scratch, times_pointer_size, roots_array_start), eax); } else { // Get return address and delta to inlined map check. __ mov(eax, factory->false_value()); @@ -5108,7 +5142,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) { __ sub(scratch, Operand(esp, 1 * kPointerSize)); if (FLAG_debug_code) { __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); - __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov); + __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); } __ mov(Operand(scratch, kDeltaToMovImmediate), eax); if (!ReturnTrueFalseObject()) { @@ -5221,7 +5255,7 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { void StringCharCodeAtGenerator::GenerateSlow( MacroAssembler* masm, const RuntimeCallHelper& call_helper) { - __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase); + __ Abort("Unexpected fallthrough to CharCodeAt slow case"); // Index is not a smi. __ bind(&index_not_smi_); @@ -5271,7 +5305,7 @@ void StringCharCodeAtGenerator::GenerateSlow( call_helper.AfterCall(masm); __ jmp(&exit_); - __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase); + __ Abort("Unexpected fallthrough from CharCodeAt slow case"); } @@ -5306,7 +5340,7 @@ void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { void StringCharFromCodeGenerator::GenerateSlow( MacroAssembler* masm, const RuntimeCallHelper& call_helper) { - __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase); + __ Abort("Unexpected fallthrough to CharFromCode slow case"); __ bind(&slow_case_); call_helper.BeforeCall(masm); @@ -5318,7 +5352,7 @@ void StringCharFromCodeGenerator::GenerateSlow( call_helper.AfterCall(masm); __ jmp(&exit_); - __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); + __ Abort("Unexpected fallthrough from CharFromCode slow case"); } @@ -5853,7 +5887,11 @@ void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, // Load the string table. Register string_table = c2; - __ LoadRoot(string_table, Heap::kStringTableRootIndex); + ExternalReference roots_array_start = + ExternalReference::roots_array_start(masm->isolate()); + __ mov(scratch, Immediate(Heap::kStringTableRootIndex)); + __ mov(string_table, + Operand::StaticArray(scratch, times_pointer_size, roots_array_start)); // Calculate capacity mask from the string table capacity. Register mask = scratch2; @@ -5941,7 +5979,12 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm, Register scratch) { // hash = (seed + character) + ((seed + character) << 10); if (Serializer::enabled()) { - __ LoadRoot(scratch, Heap::kHashSeedRootIndex); + ExternalReference roots_array_start = + ExternalReference::roots_array_start(masm->isolate()); + __ mov(scratch, Immediate(Heap::kHashSeedRootIndex)); + __ mov(scratch, Operand::StaticArray(scratch, + times_pointer_size, + roots_array_start)); __ SmiUntag(scratch); __ add(scratch, character); __ mov(hash, scratch); @@ -7439,7 +7482,7 @@ static void CreateArrayDispatch(MacroAssembler* masm) { } // If we reached this point there is a problem. - __ Abort(kUnexpectedElementsKindInArrayConstructor); + __ Abort("Unexpected ElementsKind in array constructor"); } @@ -7502,7 +7545,7 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm) { } // If we reached this point there is a problem. - __ Abort(kUnexpectedElementsKindInArrayConstructor); + __ Abort("Unexpected ElementsKind in array constructor"); } @@ -7567,9 +7610,9 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) { __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); // Will both indicate a NULL and a Smi. __ test(ecx, Immediate(kSmiTagMask)); - __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction); + __ Assert(not_zero, "Unexpected initial map for Array function"); __ CmpObjectType(ecx, MAP_TYPE, ecx); - __ Assert(equal, kUnexpectedInitialMapForArrayFunction); + __ Assert(equal, "Unexpected initial map for Array function"); // We should either have undefined in ebx or a valid cell Label okay_here; @@ -7577,7 +7620,7 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) { __ cmp(ebx, Immediate(undefined_sentinel)); __ j(equal, &okay_here); __ cmp(FieldOperand(ebx, 0), Immediate(cell_map)); - __ Assert(equal, kExpectedPropertyCellInRegisterEbx); + __ Assert(equal, "Expected property cell in register ebx"); __ bind(&okay_here); } @@ -7681,9 +7724,9 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); // Will both indicate a NULL and a Smi. __ test(ecx, Immediate(kSmiTagMask)); - __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction); + __ Assert(not_zero, "Unexpected initial map for Array function"); __ CmpObjectType(ecx, MAP_TYPE, ecx); - __ Assert(equal, kUnexpectedInitialMapForArrayFunction); + __ Assert(equal, "Unexpected initial map for Array function"); } // Figure out the right elements kind @@ -7702,7 +7745,7 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { __ j(equal, &done); __ cmp(ecx, Immediate(FAST_HOLEY_ELEMENTS)); __ Assert(equal, - kInvalidElementsKindForInternalArrayOrInternalPackedArray); + "Invalid ElementsKind for InternalArray or InternalPackedArray"); __ bind(&done); } diff --git a/chromium/v8/src/ia32/codegen-ia32.cc b/chromium/v8/src/ia32/codegen-ia32.cc index 28b0f4ad82f..f488718dc6d 100644 --- a/chromium/v8/src/ia32/codegen-ia32.cc +++ b/chromium/v8/src/ia32/codegen-ia32.cc @@ -779,7 +779,7 @@ void ElementsTransitionGenerator::GenerateSmiToDouble( if (FLAG_debug_code) { __ cmp(ebx, masm->isolate()->factory()->the_hole_value()); - __ Assert(equal, kObjectFoundInSmiOnlyArray); + __ Assert(equal, "object found in smi-only array"); } if (CpuFeatures::IsSupported(SSE2)) { @@ -1011,7 +1011,7 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm, // Assert that we do not have a cons or slice (indirect strings) here. // Sequential strings have already been ruled out. __ test(result, Immediate(kIsIndirectStringMask)); - __ Assert(zero, kExternalStringExpectedButNotFound); + __ Assert(zero, "external string expected, but not found"); } // Rule out short external strings. STATIC_CHECK(kShortExternalStringTag != 0); diff --git a/chromium/v8/src/ia32/debug-ia32.cc b/chromium/v8/src/ia32/debug-ia32.cc index fd703dcc0c7..68199f905b5 100644 --- a/chromium/v8/src/ia32/debug-ia32.cc +++ b/chromium/v8/src/ia32/debug-ia32.cc @@ -128,7 +128,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, if ((non_object_regs & (1 << r)) != 0) { if (FLAG_debug_code) { __ test(reg, Immediate(0xc0000000)); - __ Assert(zero, kUnableToEncodeValueAsSmi); + __ Assert(zero, "Unable to encode value as smi"); } __ SmiTag(reg); __ push(reg); diff --git a/chromium/v8/src/ia32/deoptimizer-ia32.cc b/chromium/v8/src/ia32/deoptimizer-ia32.cc index a9bd8c50b72..48968064aa3 100644 --- a/chromium/v8/src/ia32/deoptimizer-ia32.cc +++ b/chromium/v8/src/ia32/deoptimizer-ia32.cc @@ -625,7 +625,7 @@ void Deoptimizer::EntryGenerator::Generate() { __ pop(ecx); if (FLAG_debug_code) { __ cmp(ecx, Immediate(kAlignmentZapValue)); - __ Assert(equal, kAlignmentMarkerExpected); + __ Assert(equal, "alignment marker expected"); } __ bind(&no_padding); } else { diff --git a/chromium/v8/src/ia32/full-codegen-ia32.cc b/chromium/v8/src/ia32/full-codegen-ia32.cc index f08a269e85b..8f11acc1bec 100644 --- a/chromium/v8/src/ia32/full-codegen-ia32.cc +++ b/chromium/v8/src/ia32/full-codegen-ia32.cc @@ -745,9 +745,9 @@ void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { // Check that we're not inside a with or catch context. __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset)); __ cmp(ebx, isolate()->factory()->with_context_map()); - __ Check(not_equal, kDeclarationInWithContext); + __ Check(not_equal, "Declaration in with context."); __ cmp(ebx, isolate()->factory()->catch_context_map()); - __ Check(not_equal, kDeclarationInCatchContext); + __ Check(not_equal, "Declaration in catch context."); } } @@ -2169,7 +2169,7 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator, __ Push(Smi::FromInt(resume_mode)); __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3); // Not reached: the runtime call returns elsewhere. - __ Abort(kGeneratorFailedToResume); + __ Abort("Generator failed to resume."); // Throw error if we attempt to operate on a running generator. __ bind(&wrong_state); @@ -2468,7 +2468,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, // Check for an uninitialized let binding. __ mov(edx, location); __ cmp(edx, isolate()->factory()->the_hole_value()); - __ Check(equal, kLetBindingReInitialization); + __ Check(equal, "Let binding re-initialization."); } // Perform the assignment. __ mov(location, eax); @@ -3430,15 +3430,15 @@ void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string, Register value, uint32_t encoding_mask) { __ test(index, Immediate(kSmiTagMask)); - __ Check(zero, kNonSmiIndex); + __ Check(zero, "Non-smi index"); __ test(value, Immediate(kSmiTagMask)); - __ Check(zero, kNonSmiValue); + __ Check(zero, "Non-smi value"); __ cmp(index, FieldOperand(string, String::kLengthOffset)); - __ Check(less, kIndexIsTooLarge); + __ Check(less, "Index is too large"); __ cmp(index, Immediate(Smi::FromInt(0))); - __ Check(greater_equal, kIndexIsNegative); + __ Check(greater_equal, "Index is negative"); __ push(value); __ mov(value, FieldOperand(string, HeapObject::kMapOffset)); @@ -3446,7 +3446,7 @@ void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string, __ and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask)); __ cmp(value, Immediate(encoding_mask)); - __ Check(equal, kUnexpectedStringType); + __ Check(equal, "Unexpected string type"); __ pop(value); } @@ -3818,7 +3818,7 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { Handle<FixedArray> jsfunction_result_caches( isolate()->native_context()->jsfunction_result_caches()); if (jsfunction_result_caches->length() <= cache_id) { - __ Abort(kAttemptToUseUndefinedCache); + __ Abort("Attempt to use undefined cache."); __ mov(eax, isolate()->factory()->undefined_value()); context()->Plug(eax); return; @@ -4000,7 +4000,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // scratch, string_length, elements. if (generate_debug_code_) { __ cmp(index, array_length); - __ Assert(less, kNoEmptyArraysHereInEmitFastAsciiArrayJoin); + __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin"); } __ bind(&loop); __ mov(string, FieldOperand(elements, @@ -4347,12 +4347,34 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { break; } + case Token::SUB: + EmitUnaryOperation(expr, "[ UnaryOperation (SUB)"); + break; + + case Token::BIT_NOT: + EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)"); + break; + default: UNREACHABLE(); } } +void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr, + const char* comment) { + Comment cmt(masm_, comment); + UnaryOpStub stub(expr->op()); + // UnaryOpStub expects the argument to be in the + // accumulator register eax. + VisitForAccumulatorValue(expr->expression()); + SetSourcePosition(expr->position()); + CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, + expr->UnaryOperationFeedbackId()); + context()->Plug(eax); +} + + void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { Comment cmnt(masm_, "[ CountOperation"); SetSourcePosition(expr->position()); diff --git a/chromium/v8/src/ia32/ic-ia32.cc b/chromium/v8/src/ia32/ic-ia32.cc index 1e0f14e7687..bf0c80b2b46 100644 --- a/chromium/v8/src/ia32/ic-ia32.cc +++ b/chromium/v8/src/ia32/ic-ia32.cc @@ -483,7 +483,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { // based on 32 bits of the map pointer and the string hash. if (FLAG_debug_code) { __ cmp(eax, FieldOperand(edx, HeapObject::kMapOffset)); - __ Check(equal, kMapIsNoLongerInEax); + __ Check(equal, "Map is no longer in eax."); } __ mov(ebx, eax); // Keep the map around for later. __ shr(eax, KeyedLookupCache::kMapHashShift); diff --git a/chromium/v8/src/ia32/lithium-codegen-ia32.cc b/chromium/v8/src/ia32/lithium-codegen-ia32.cc index 19c553bfa51..7a601cf39bc 100644 --- a/chromium/v8/src/ia32/lithium-codegen-ia32.cc +++ b/chromium/v8/src/ia32/lithium-codegen-ia32.cc @@ -113,7 +113,7 @@ void LCodeGen::FinishCode(Handle<Code> code) { } -void LCodeGen::Abort(BailoutReason reason) { +void LCodeGen::Abort(const char* reason) { info()->set_bailout_reason(reason); status_ = ABORTED; } @@ -220,7 +220,7 @@ bool LCodeGen::GeneratePrologue() { dynamic_frame_alignment_ && FLAG_debug_code) { __ test(esp, Immediate(kPointerSize)); - __ Assert(zero, kFrameIsExpectedToBeAligned); + __ Assert(zero, "frame is expected to be aligned"); } // Reserve space for the stack slots needed by the code. @@ -355,8 +355,6 @@ bool LCodeGen::GenerateBody() { if (!CpuFeatures::IsSupported(SSE2)) FlushX87StackIfNecessary(instr); - RecordAndUpdatePosition(instr->position()); - instr->CompileToNative(this); if (!CpuFeatures::IsSupported(SSE2)) { @@ -424,10 +422,6 @@ bool LCodeGen::GenerateDeferredCode() { if (deferred_.length() > 0) { for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { LDeferredCode* code = deferred_[i]; - - int pos = instructions_->at(code->instruction_index())->position(); - RecordAndUpdatePosition(pos); - Comment(";;; <@%d,#%d> " "-------------------- Deferred %s --------------------", code->instruction_index(), @@ -769,57 +763,37 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, UNREACHABLE(); } - int object_index = 0; - int dematerialized_index = 0; for (int i = 0; i < translation_size; ++i) { LOperand* value = environment->values()->at(i); - AddToTranslation(environment, - translation, + + // TODO(mstarzinger): Introduce marker operands to indicate that this value + // is not present and must be reconstructed from the deoptimizer. Currently + // this is only used for the arguments object. + if (value == NULL) { + int arguments_count = environment->values()->length() - translation_size; + translation->BeginArgumentsObject(arguments_count); + for (int i = 0; i < arguments_count; ++i) { + LOperand* value = environment->values()->at(translation_size + i); + AddToTranslation(translation, + value, + environment->HasTaggedValueAt(translation_size + i), + environment->HasUint32ValueAt(translation_size + i)); + } + continue; + } + + AddToTranslation(translation, value, environment->HasTaggedValueAt(i), - environment->HasUint32ValueAt(i), - &object_index, - &dematerialized_index); + environment->HasUint32ValueAt(i)); } } -void LCodeGen::AddToTranslation(LEnvironment* environment, - Translation* translation, +void LCodeGen::AddToTranslation(Translation* translation, LOperand* op, bool is_tagged, - bool is_uint32, - int* object_index_pointer, - int* dematerialized_index_pointer) { - if (op == LEnvironment::materialization_marker()) { - int object_index = (*object_index_pointer)++; - if (environment->ObjectIsDuplicateAt(object_index)) { - int dupe_of = environment->ObjectDuplicateOfAt(object_index); - translation->DuplicateObject(dupe_of); - return; - } - int object_length = environment->ObjectLengthAt(object_index); - if (environment->ObjectIsArgumentsAt(object_index)) { - translation->BeginArgumentsObject(object_length); - } else { - translation->BeginCapturedObject(object_length); - } - int dematerialized_index = *dematerialized_index_pointer; - int env_offset = environment->translation_size() + dematerialized_index; - *dematerialized_index_pointer += object_length; - for (int i = 0; i < object_length; ++i) { - LOperand* value = environment->values()->at(env_offset + i); - AddToTranslation(environment, - translation, - value, - environment->HasTaggedValueAt(env_offset + i), - environment->HasUint32ValueAt(env_offset + i), - object_index_pointer, - dematerialized_index_pointer); - } - return; - } - + bool is_uint32) { if (op->IsStackSlot()) { if (is_tagged) { translation->StoreStackSlot(op->index()); @@ -908,7 +882,7 @@ void LCodeGen::LoadContextFromDeferred(LOperand* context) { } else if (context->IsConstantOperand()) { HConstant* constant = chunk_->LookupConstant(LConstantOperand::cast(context)); - __ LoadObject(esi, Handle<Object>::cast(constant->handle())); + __ LoadHeapObject(esi, Handle<Context>::cast(constant->handle())); } else { UNREACHABLE(); } @@ -974,7 +948,7 @@ void LCodeGen::DeoptimizeIf(Condition cc, Address entry = Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type); if (entry == NULL) { - Abort(kBailoutWasNotPrepared); + Abort("bailout was not prepared"); return; } @@ -1010,7 +984,7 @@ void LCodeGen::DeoptimizeIf(Condition cc, __ bind(&done); } - if (info()->ShouldTrapOnDeopt()) { + if (FLAG_trap_on_deopt && info()->IsOptimizing()) { Label done; if (cc != no_condition) __ j(NegateCondition(cc), &done, Label::kNear); __ int3(); @@ -1194,14 +1168,6 @@ void LCodeGen::RecordPosition(int position) { } -void LCodeGen::RecordAndUpdatePosition(int position) { - if (position >= 0 && position != old_position_) { - masm()->positions_recorder()->RecordPosition(position); - old_position_ = position; - } -} - - static const char* LabelType(LLabel* label) { if (label->is_loop_header()) return " (loop header)"; if (label->is_osr_entry()) return " (OSR entry)"; @@ -1713,9 +1679,8 @@ void LCodeGen::DoBitI(LBitI* instr) { ASSERT(left->IsRegister()); if (right->IsConstantOperand()) { - int32_t right_operand = - ToRepresentation(LConstantOperand::cast(right), - instr->hydrogen()->representation()); + int right_operand = ToRepresentation(LConstantOperand::cast(right), + instr->hydrogen()->representation()); switch (instr->op()) { case Token::BIT_AND: __ and_(ToRegister(left), right_operand); @@ -1724,11 +1689,7 @@ void LCodeGen::DoBitI(LBitI* instr) { __ or_(ToRegister(left), right_operand); break; case Token::BIT_XOR: - if (right_operand == int32_t(~0)) { - __ not_(ToRegister(left)); - } else { - __ xor_(ToRegister(left), right_operand); - } + __ xor_(ToRegister(left), right_operand); break; default: UNREACHABLE(); @@ -2015,7 +1976,7 @@ void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; __ cmp(value, Immediate(encoding == String::ONE_BYTE_ENCODING ? one_byte_seq_type : two_byte_seq_type)); - __ Check(equal, kUnexpectedStringType); + __ Check(equal, "Unexpected string type"); __ pop(value); } @@ -2029,6 +1990,13 @@ void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { } +void LCodeGen::DoBitNotI(LBitNotI* instr) { + LOperand* input = instr->value(); + ASSERT(input->Equals(instr->result())); + __ not_(ToRegister(input)); +} + + void LCodeGen::DoThrow(LThrow* instr) { __ push(ToOperand(instr->value())); ASSERT(ToRegister(instr->context()).is(esi)); @@ -2233,17 +2201,6 @@ void LCodeGen::EmitBranch(InstrType instr, Condition cc) { } -template<class InstrType> -void LCodeGen::EmitFalseBranch(InstrType instr, Condition cc) { - int false_block = instr->FalseDestination(chunk_); - if (cc == no_condition) { - __ jmp(chunk_->GetAssemblyLabel(false_block)); - } else { - __ j(cc, chunk_->GetAssemblyLabel(false_block)); - } -} - - void LCodeGen::DoIsNumberAndBranch(LIsNumberAndBranch* instr) { Representation r = instr->hydrogen()->value()->representation(); if (r.IsSmiOrInteger32() || r.IsDouble()) { @@ -2494,51 +2451,6 @@ void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { } -void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) { - if (instr->hydrogen()->representation().IsTagged()) { - Register input_reg = ToRegister(instr->object()); - __ cmp(input_reg, factory()->the_hole_value()); - EmitBranch(instr, equal); - return; - } - - bool use_sse2 = CpuFeatures::IsSupported(SSE2); - if (use_sse2) { - CpuFeatureScope scope(masm(), SSE2); - XMMRegister input_reg = ToDoubleRegister(instr->object()); - __ ucomisd(input_reg, input_reg); - EmitFalseBranch(instr, parity_odd); - } else { - // Put the value to the top of stack - X87Register src = ToX87Register(instr->object()); - X87LoadForUsage(src); - __ fld(0); - __ fld(0); - __ FCmp(); - Label ok; - __ j(parity_even, &ok); - __ fstp(0); - EmitFalseBranch(instr, no_condition); - __ bind(&ok); - } - - - __ sub(esp, Immediate(kDoubleSize)); - if (use_sse2) { - CpuFeatureScope scope(masm(), SSE2); - XMMRegister input_reg = ToDoubleRegister(instr->object()); - __ movdbl(MemOperand(esp, 0), input_reg); - } else { - __ fstp_d(MemOperand(esp, 0)); - } - - __ add(esp, Immediate(kDoubleSize)); - int offset = sizeof(kHoleNanUpper32); - __ cmp(MemOperand(esp, -offset), Immediate(kHoleNanUpper32)); - EmitBranch(instr, equal); -} - - Condition LCodeGen::EmitIsObject(Register input, Register temp1, Label* is_not_object, @@ -2951,7 +2863,7 @@ void LCodeGen::EmitReturn(LReturn* instr, bool dynamic_frame_alignment) { __ cmp(Operand(esp, (parameter_count + extra_value_count) * kPointerSize), Immediate(kAlignmentZapValue)); - __ Assert(equal, kExpectedAlignmentMarker); + __ Assert(equal, "expected alignment marker"); } __ Ret((parameter_count + extra_value_count) * kPointerSize, ecx); } else { @@ -2964,7 +2876,7 @@ void LCodeGen::EmitReturn(LReturn* instr, bool dynamic_frame_alignment) { __ cmp(Operand(esp, reg, times_pointer_size, extra_value_count * kPointerSize), Immediate(kAlignmentZapValue)); - __ Assert(equal, kExpectedAlignmentMarker); + __ Assert(equal, "expected alignment marker"); } // emit code to restore stack based on instr->parameter_count() @@ -3178,6 +3090,47 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { } +void LCodeGen::EmitLoadFieldOrConstant(Register result, + Register object, + Handle<Map> type, + Handle<String> name, + LEnvironment* env) { + LookupResult lookup(isolate()); + type->LookupDescriptor(NULL, *name, &lookup); + ASSERT(lookup.IsFound() || lookup.IsCacheable()); + if (lookup.IsField()) { + int index = lookup.GetLocalFieldIndexFromMap(*type); + int offset = index * kPointerSize; + if (index < 0) { + // Negative property indices are in-object properties, indexed + // from the end of the fixed part of the object. + __ mov(result, FieldOperand(object, offset + type->instance_size())); + } else { + // Non-negative property indices are in the properties array. + __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset)); + __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize)); + } + } else if (lookup.IsConstant()) { + Handle<Object> constant(lookup.GetConstantFromMap(*type), isolate()); + __ LoadObject(result, constant); + } else { + // Negative lookup. + // Check prototypes. + Handle<HeapObject> current(HeapObject::cast((*type)->prototype())); + Heap* heap = type->GetHeap(); + while (*current != heap->null_value()) { + __ LoadHeapObject(result, current); + __ cmp(FieldOperand(result, HeapObject::kMapOffset), + Handle<Map>(current->map())); + DeoptimizeIf(not_equal, env); + current = + Handle<HeapObject>(HeapObject::cast(current->map()->prototype())); + } + __ mov(result, factory()->undefined_value()); + } +} + + void LCodeGen::EmitPushTaggedOperand(LOperand* operand) { ASSERT(!operand->IsDoubleRegister()); if (operand->IsConstantOperand()) { @@ -3196,6 +3149,68 @@ void LCodeGen::EmitPushTaggedOperand(LOperand* operand) { } +// Check for cases where EmitLoadFieldOrConstantFunction needs to walk the +// prototype chain, which causes unbounded code generation. +static bool CompactEmit(SmallMapList* list, + Handle<String> name, + int i, + Isolate* isolate) { + Handle<Map> map = list->at(i); + LookupResult lookup(isolate); + map->LookupDescriptor(NULL, *name, &lookup); + return lookup.IsField() || lookup.IsConstant(); +} + + +void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) { + Register object = ToRegister(instr->object()); + Register result = ToRegister(instr->result()); + + int map_count = instr->hydrogen()->types()->length(); + bool need_generic = instr->hydrogen()->need_generic(); + + if (map_count == 0 && !need_generic) { + DeoptimizeIf(no_condition, instr->environment()); + return; + } + Handle<String> name = instr->hydrogen()->name(); + Label done; + bool all_are_compact = true; + for (int i = 0; i < map_count; ++i) { + if (!CompactEmit(instr->hydrogen()->types(), name, i, isolate())) { + all_are_compact = false; + break; + } + } + for (int i = 0; i < map_count; ++i) { + bool last = (i == map_count - 1); + Handle<Map> map = instr->hydrogen()->types()->at(i); + Label check_passed; + __ CompareMap(object, map, &check_passed); + if (last && !need_generic) { + DeoptimizeIf(not_equal, instr->environment()); + __ bind(&check_passed); + EmitLoadFieldOrConstant(result, object, map, name, instr->environment()); + } else { + Label next; + bool compact = all_are_compact ? true : + CompactEmit(instr->hydrogen()->types(), name, i, isolate()); + __ j(not_equal, &next, compact ? Label::kNear : Label::kFar); + __ bind(&check_passed); + EmitLoadFieldOrConstant(result, object, map, name, instr->environment()); + __ jmp(&done, all_are_compact ? Label::kNear : Label::kFar); + __ bind(&next); + } + } + if (need_generic) { + __ mov(ecx, name); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); + CallCode(ic, RelocInfo::CODE_TARGET, instr); + } + __ bind(&done); +} + + void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { ASSERT(ToRegister(instr->context()).is(esi)); ASSERT(ToRegister(instr->object()).is(edx)); @@ -3432,7 +3447,7 @@ Operand LCodeGen::BuildFastArrayOperand( if (key->IsConstantOperand()) { int constant_value = ToInteger32(LConstantOperand::cast(key)); if (constant_value & 0xF0000000) { - Abort(kArrayIndexConstantValueTooBig); + Abort("array index constant value too big"); } return Operand(elements_pointer_reg, ((constant_value + additional_index) << shift_size) @@ -3806,7 +3821,7 @@ void LCodeGen::DoMathAbs(LMathAbs* instr) { __ xorps(scratch, scratch); __ subsd(scratch, input_reg); __ pand(input_reg, scratch); - } else if (r.IsSmiOrInteger32()) { + } else if (r.IsInteger32()) { EmitIntegerMathAbs(instr); } else { // Tagged case. DeferredMathAbsTaggedHeapNumber* deferred = @@ -4148,9 +4163,6 @@ void LCodeGen::DoMathExp(LMathExp* instr) { void LCodeGen::DoMathTan(LMathTan* instr) { ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); - // Set the context register to a GC-safe fake value. Clobbering it is - // OK because this instruction is marked as a call. - __ Set(esi, Immediate(0)); TranscendentalCacheStub stub(TranscendentalCache::TAN, TranscendentalCacheStub::UNTAGGED); CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); @@ -4159,9 +4171,6 @@ void LCodeGen::DoMathTan(LMathTan* instr) { void LCodeGen::DoMathCos(LMathCos* instr) { ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); - // Set the context register to a GC-safe fake value. Clobbering it is - // OK because this instruction is marked as a call. - __ Set(esi, Immediate(0)); TranscendentalCacheStub stub(TranscendentalCache::COS, TranscendentalCacheStub::UNTAGGED); CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); @@ -4170,9 +4179,6 @@ void LCodeGen::DoMathCos(LMathCos* instr) { void LCodeGen::DoMathSin(LMathSin* instr) { ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); - // Set the context register to a GC-safe fake value. Clobbering it is - // OK because this instruction is marked as a call. - __ Set(esi, Immediate(0)); TranscendentalCacheStub stub(TranscendentalCache::SIN, TranscendentalCacheStub::UNTAGGED); CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); @@ -5045,6 +5051,13 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { Register reg = ToRegister(instr->result()); + bool convert_hole = false; + HValue* change_input = instr->hydrogen()->value(); + if (change_input->IsLoadKeyed()) { + HLoadKeyed* load = HLoadKeyed::cast(change_input); + convert_hole = load->UsesMustHandleHole(); + } + bool use_sse2 = CpuFeatures::IsSupported(SSE2); if (!use_sse2) { // Put the value to the top of stack @@ -5052,6 +5065,54 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { X87LoadForUsage(src); } + Label no_special_nan_handling; + Label done; + if (convert_hole) { + if (use_sse2) { + CpuFeatureScope scope(masm(), SSE2); + XMMRegister input_reg = ToDoubleRegister(instr->value()); + __ ucomisd(input_reg, input_reg); + } else { + __ fld(0); + __ fld(0); + __ FCmp(); + } + + __ j(parity_odd, &no_special_nan_handling); + __ sub(esp, Immediate(kDoubleSize)); + if (use_sse2) { + CpuFeatureScope scope(masm(), SSE2); + XMMRegister input_reg = ToDoubleRegister(instr->value()); + __ movdbl(MemOperand(esp, 0), input_reg); + } else { + __ fld(0); + __ fstp_d(MemOperand(esp, 0)); + } + __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)), + Immediate(kHoleNanUpper32)); + Label canonicalize; + __ j(not_equal, &canonicalize); + __ add(esp, Immediate(kDoubleSize)); + __ mov(reg, factory()->the_hole_value()); + if (!use_sse2) { + __ fstp(0); + } + __ jmp(&done); + __ bind(&canonicalize); + __ add(esp, Immediate(kDoubleSize)); + ExternalReference nan = + ExternalReference::address_of_canonical_non_hole_nan(); + if (use_sse2) { + CpuFeatureScope scope(masm(), SSE2); + XMMRegister input_reg = ToDoubleRegister(instr->value()); + __ movdbl(input_reg, Operand::StaticVariable(nan)); + } else { + __ fstp(0); + __ fld_d(Operand::StaticVariable(nan)); + } + } + + __ bind(&no_special_nan_handling); DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr); if (FLAG_inline_new) { Register tmp = ToRegister(instr->temp()); @@ -5067,6 +5128,7 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { } else { __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset)); } + __ bind(&done); } @@ -5116,21 +5178,23 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg, Register temp_reg, X87Register res_reg, - bool can_convert_undefined_to_nan, + bool allow_undefined_as_nan, bool deoptimize_on_minus_zero, LEnvironment* env, NumberUntagDMode mode) { Label load_smi, done; X87PrepareToWrite(res_reg); - if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) { + STATIC_ASSERT(NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE > + NUMBER_CANDIDATE_IS_ANY_TAGGED); + if (mode >= NUMBER_CANDIDATE_IS_ANY_TAGGED) { // Smi check. __ JumpIfSmi(input_reg, &load_smi, Label::kNear); // Heap number map check. __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), factory()->heap_number_map()); - if (!can_convert_undefined_to_nan) { + if (!allow_undefined_as_nan) { DeoptimizeIf(not_equal, env); } else { Label heap_number, convert; @@ -5138,6 +5202,10 @@ void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg, // Convert undefined (or hole) to NaN. __ cmp(input_reg, factory()->undefined_value()); + if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE) { + __ j(equal, &convert, Label::kNear); + __ cmp(input_reg, factory()->the_hole_value()); + } DeoptimizeIf(not_equal, env); __ bind(&convert); @@ -5184,20 +5252,22 @@ void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg, void LCodeGen::EmitNumberUntagD(Register input_reg, Register temp_reg, XMMRegister result_reg, - bool can_convert_undefined_to_nan, + bool allow_undefined_as_nan, bool deoptimize_on_minus_zero, LEnvironment* env, NumberUntagDMode mode) { Label load_smi, done; - if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) { + STATIC_ASSERT(NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE > + NUMBER_CANDIDATE_IS_ANY_TAGGED); + if (mode >= NUMBER_CANDIDATE_IS_ANY_TAGGED) { // Smi check. __ JumpIfSmi(input_reg, &load_smi, Label::kNear); // Heap number map check. __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), factory()->heap_number_map()); - if (!can_convert_undefined_to_nan) { + if (!allow_undefined_as_nan) { DeoptimizeIf(not_equal, env); } else { Label heap_number, convert; @@ -5205,6 +5275,10 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, // Convert undefined (and hole) to NaN. __ cmp(input_reg, factory()->undefined_value()); + if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE) { + __ j(equal, &convert, Label::kNear); + __ cmp(input_reg, factory()->the_hole_value()); + } DeoptimizeIf(not_equal, env); __ bind(&convert); @@ -5529,9 +5603,16 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { instr->hydrogen()->deoptimize_on_minus_zero(); Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg; + NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED; HValue* value = instr->hydrogen()->value(); - NumberUntagDMode mode = value->representation().IsSmi() - ? NUMBER_CANDIDATE_IS_SMI : NUMBER_CANDIDATE_IS_ANY_TAGGED; + if (value->representation().IsSmi()) { + mode = NUMBER_CANDIDATE_IS_SMI; + } else if (value->IsLoadKeyed()) { + HLoadKeyed* load = HLoadKeyed::cast(value); + if (load->UsesMustHandleHole()) { + mode = NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE; + } + } if (CpuFeatures::IsSupported(SSE2)) { CpuFeatureScope scope(masm(), SSE2); @@ -5539,7 +5620,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { EmitNumberUntagD(input_reg, temp_reg, result_reg, - instr->hydrogen()->can_convert_undefined_to_nan(), + instr->hydrogen()->allow_undefined_as_nan(), deoptimize_on_minus_zero, instr->environment(), mode); @@ -5547,7 +5628,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { EmitNumberUntagDNoSSE2(input_reg, temp_reg, ToX87Register(instr->result()), - instr->hydrogen()->can_convert_undefined_to_nan(), + instr->hydrogen()->allow_undefined_as_nan(), deoptimize_on_minus_zero, instr->environment(), mode); @@ -5712,68 +5793,31 @@ void LCodeGen::DoCheckFunction(LCheckFunction* instr) { } -void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) { - { - PushSafepointRegistersScope scope(this); - __ push(object); - __ xor_(esi, esi); - __ CallRuntimeSaveDoubles(Runtime::kMigrateInstance); - RecordSafepointWithRegisters( - instr->pointer_map(), 1, Safepoint::kNoLazyDeopt); - - __ test(eax, Immediate(kSmiTagMask)); - } - DeoptimizeIf(zero, instr->environment()); +void LCodeGen::DoCheckMapCommon(Register reg, + Handle<Map> map, + LInstruction* instr) { + Label success; + __ CompareMap(reg, map, &success); + DeoptimizeIf(not_equal, instr->environment()); + __ bind(&success); } void LCodeGen::DoCheckMaps(LCheckMaps* instr) { - class DeferredCheckMaps: public LDeferredCode { - public: - DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object) - : LDeferredCode(codegen), instr_(instr), object_(object) { - SetExit(check_maps()); - } - virtual void Generate() { - codegen()->DoDeferredInstanceMigration(instr_, object_); - } - Label* check_maps() { return &check_maps_; } - virtual LInstruction* instr() { return instr_; } - private: - LCheckMaps* instr_; - Label check_maps_; - Register object_; - }; - if (instr->hydrogen()->CanOmitMapChecks()) return; - LOperand* input = instr->value(); ASSERT(input->IsRegister()); Register reg = ToRegister(input); - SmallMapList* map_set = instr->hydrogen()->map_set(); - - DeferredCheckMaps* deferred = NULL; - if (instr->hydrogen()->has_migration_target()) { - deferred = new(zone()) DeferredCheckMaps(this, instr, reg); - __ bind(deferred->check_maps()); - } - Label success; + SmallMapList* map_set = instr->hydrogen()->map_set(); for (int i = 0; i < map_set->length() - 1; i++) { Handle<Map> map = map_set->at(i); __ CompareMap(reg, map, &success); __ j(equal, &success); } - Handle<Map> map = map_set->last(); - __ CompareMap(reg, map, &success); - if (instr->hydrogen()->has_migration_target()) { - __ j(not_equal, deferred->entry()); - } else { - DeoptimizeIf(not_equal, instr->environment()); - } - + DoCheckMapCommon(reg, map, instr); __ bind(&success); } @@ -5950,6 +5994,22 @@ void LCodeGen::DoClampTToUint8NoSSE2(LClampTToUint8NoSSE2* instr) { } +void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { + if (instr->hydrogen()->CanOmitPrototypeChecks()) return; + Register reg = ToRegister(instr->temp()); + + ZoneList<Handle<JSObject> >* prototypes = instr->prototypes(); + ZoneList<Handle<Map> >* maps = instr->maps(); + + ASSERT(prototypes->length() == maps->length()); + + for (int i = 0; i < prototypes->length(); i++) { + __ LoadHeapObject(reg, prototypes->at(i)); + DoCheckMapCommon(reg, maps->at(i), instr); + } +} + + void LCodeGen::DoAllocate(LAllocate* instr) { class DeferredAllocate: public LDeferredCode { public: @@ -6277,7 +6337,6 @@ void LCodeGen::DoDeoptimize(LDeoptimize* instr) { if (info()->IsStub() && type == Deoptimizer::EAGER) { type = Deoptimizer::LAZY; } - Comment(";;; deoptimize: %s", instr->hydrogen()->reason()); DeoptimizeIf(no_condition, instr->environment(), type); } diff --git a/chromium/v8/src/ia32/lithium-codegen-ia32.h b/chromium/v8/src/ia32/lithium-codegen-ia32.h index aa8f6c248a3..0beef85f0bc 100644 --- a/chromium/v8/src/ia32/lithium-codegen-ia32.h +++ b/chromium/v8/src/ia32/lithium-codegen-ia32.h @@ -71,8 +71,7 @@ class LCodeGen BASE_EMBEDDED { x87_stack_depth_(0), safepoints_(info->zone()), resolver_(this), - expected_safepoint_kind_(Safepoint::kSimple), - old_position_(RelocInfo::kNoPosition) { + expected_safepoint_kind_(Safepoint::kSimple) { PopulateDeoptimizationLiteralsWithInlinedFunctions(); } @@ -164,7 +163,8 @@ class LCodeGen BASE_EMBEDDED { void DoDeferredAllocate(LAllocate* instr); void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, Label* map_check); - void DoDeferredInstanceMigration(LCheckMaps* instr, Register object); + + void DoCheckMapCommon(Register reg, Handle<Map> map, LInstruction* instr); // Parallel move support. void DoParallelMove(LParallelMove* move); @@ -212,7 +212,7 @@ class LCodeGen BASE_EMBEDDED { int GetStackSlotCount() const { return chunk()->spill_slot_count(); } - void Abort(BailoutReason reason); + void Abort(const char* reason); void FPRINTF_CHECKING Comment(const char* format, ...); void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); } @@ -282,13 +282,10 @@ class LCodeGen BASE_EMBEDDED { void DeoptimizeIf(Condition cc, LEnvironment* environment); void ApplyCheckIf(Condition cc, LBoundsCheck* check); - void AddToTranslation(LEnvironment* environment, - Translation* translation, + void AddToTranslation(Translation* translation, LOperand* op, bool is_tagged, - bool is_uint32, - int* object_index_pointer, - int* dematerialized_index_pointer); + bool is_uint32); void RegisterDependentCodeForEmbeddedMaps(Handle<Code> code); void PopulateDeoptimizationData(Handle<Code> code); int DefineDeoptimizationLiteral(Handle<Object> literal); @@ -298,7 +295,7 @@ class LCodeGen BASE_EMBEDDED { Register ToRegister(int index) const; XMMRegister ToDoubleRegister(int index) const; X87Register ToX87Register(int index) const; - int32_t ToRepresentation(LConstantOperand* op, const Representation& r) const; + int ToRepresentation(LConstantOperand* op, const Representation& r) const; int32_t ToInteger32(LConstantOperand* op) const; ExternalReference ToExternalReference(LConstantOperand* op) const; @@ -323,14 +320,10 @@ class LCodeGen BASE_EMBEDDED { Safepoint::DeoptMode mode); void RecordPosition(int position); - void RecordAndUpdatePosition(int position); - static Condition TokenToCondition(Token::Value op, bool is_unsigned); void EmitGoto(int block); template<class InstrType> void EmitBranch(InstrType instr, Condition cc); - template<class InstrType> - void EmitFalseBranch(InstrType instr, Condition cc); void EmitNumberUntagD( Register input, Register temp, @@ -377,6 +370,12 @@ class LCodeGen BASE_EMBEDDED { // Caller should branch on equal condition. void EmitIsConstructCall(Register temp); + void EmitLoadFieldOrConstant(Register result, + Register object, + Handle<Map> type, + Handle<String> name, + LEnvironment* env); + // Emits optimized code to deep-copy the contents of statically known // object graphs (e.g. object literal boilerplate). void EmitDeepCopy(Handle<JSObject> object, @@ -450,8 +449,6 @@ class LCodeGen BASE_EMBEDDED { Safepoint::Kind expected_safepoint_kind_; - int old_position_; - class PushSafepointRegistersScope BASE_EMBEDDED { public: explicit PushSafepointRegistersScope(LCodeGen* codegen) diff --git a/chromium/v8/src/ia32/lithium-ia32.cc b/chromium/v8/src/ia32/lithium-ia32.cc index b3158685fcf..ea07c5a1991 100644 --- a/chromium/v8/src/ia32/lithium-ia32.cc +++ b/chromium/v8/src/ia32/lithium-ia32.cc @@ -487,7 +487,7 @@ LPlatformChunk* LChunkBuilder::Build() { } -void LChunkBuilder::Abort(BailoutReason reason) { +void LChunkBuilder::Abort(const char* reason) { info()->set_bailout_reason(reason); status_ = ABORTED; } @@ -645,10 +645,8 @@ LInstruction* LChunkBuilder::DefineFixedDouble( LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) { HEnvironment* hydrogen_env = current_block_->last_environment(); int argument_index_accumulator = 0; - ZoneList<HValue*> objects_to_materialize(0, zone()); instr->set_environment(CreateEnvironment(hydrogen_env, - &argument_index_accumulator, - &objects_to_materialize)); + &argument_index_accumulator)); return instr; } @@ -700,7 +698,7 @@ LUnallocated* LChunkBuilder::TempRegister() { new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER); int vreg = allocator_->GetVirtualRegister(); if (!allocator_->AllocationOk()) { - Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister); + Abort("Out of virtual registers while trying to allocate temp register."); vreg = 0; } operand->set_virtual_register(vreg); @@ -940,7 +938,6 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { } #endif - instr->set_position(position_); if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) { instr = AssignPointerMap(instr); } @@ -956,13 +953,11 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { LEnvironment* LChunkBuilder::CreateEnvironment( HEnvironment* hydrogen_env, - int* argument_index_accumulator, - ZoneList<HValue*>* objects_to_materialize) { + int* argument_index_accumulator) { if (hydrogen_env == NULL) return NULL; - LEnvironment* outer = CreateEnvironment(hydrogen_env->outer(), - argument_index_accumulator, - objects_to_materialize); + LEnvironment* outer = + CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator); BailoutId ast_id = hydrogen_env->ast_id(); ASSERT(!ast_id.IsNone() || hydrogen_env->frame_type() != JS_FUNCTION); @@ -977,16 +972,16 @@ LEnvironment* LChunkBuilder::CreateEnvironment( outer, hydrogen_env->entry(), zone()); + bool needs_arguments_object_materialization = false; int argument_index = *argument_index_accumulator; - int object_index = objects_to_materialize->length(); for (int i = 0; i < hydrogen_env->length(); ++i) { if (hydrogen_env->is_special_index(i)) continue; - LOperand* op; HValue* value = hydrogen_env->values()->at(i); - if (value->IsArgumentsObject() || value->IsCapturedObject()) { - objects_to_materialize->Add(value, zone()); - op = LEnvironment::materialization_marker(); + LOperand* op = NULL; + if (value->IsArgumentsObject()) { + needs_arguments_object_materialization = true; + op = NULL; } else if (value->IsPushArgument()) { op = new(zone()) LArgument(argument_index++); } else { @@ -997,33 +992,15 @@ LEnvironment* LChunkBuilder::CreateEnvironment( value->CheckFlag(HInstruction::kUint32)); } - for (int i = object_index; i < objects_to_materialize->length(); ++i) { - HValue* object_to_materialize = objects_to_materialize->at(i); - int previously_materialized_object = -1; - for (int prev = 0; prev < i; ++prev) { - if (objects_to_materialize->at(prev) == objects_to_materialize->at(i)) { - previously_materialized_object = prev; - break; - } - } - int length = object_to_materialize->OperandCount(); - bool is_arguments = object_to_materialize->IsArgumentsObject(); - if (previously_materialized_object >= 0) { - result->AddDuplicateObject(previously_materialized_object); - continue; - } else { - result->AddNewObject(is_arguments ? length - 1 : length, is_arguments); - } - for (int i = is_arguments ? 1 : 0; i < length; ++i) { - LOperand* op; - HValue* value = object_to_materialize->OperandAt(i); - if (value->IsArgumentsObject() || value->IsCapturedObject()) { - objects_to_materialize->Add(value, zone()); - op = LEnvironment::materialization_marker(); - } else { - ASSERT(!value->IsPushArgument()); - op = UseAny(value); - } + if (needs_arguments_object_materialization) { + HArgumentsObject* arguments = hydrogen_env->entry() == NULL + ? graph()->GetArgumentsObject() + : hydrogen_env->entry()->arguments_object(); + ASSERT(arguments->IsLinked()); + for (int i = 1; i < arguments->arguments_count(); ++i) { + HValue* value = arguments->arguments_values()->at(i); + ASSERT(!value->IsArgumentsObject() && !value->IsPushArgument()); + LOperand* op = UseAny(value); result->AddValue(op, value->representation(), value->CheckFlag(HInstruction::kUint32)); @@ -1415,8 +1392,9 @@ LInstruction* LChunkBuilder::DoShl(HShl* instr) { LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { if (instr->representation().IsSmiOrInteger32()) { - ASSERT(instr->left()->representation().Equals(instr->representation())); - ASSERT(instr->right()->representation().Equals(instr->representation())); + ASSERT(instr->left()->representation().IsSmiOrInteger32()); + ASSERT(instr->right()->representation().Equals( + instr->left()->representation())); LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand()); LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand()); @@ -1436,6 +1414,16 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { } +LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) { + ASSERT(instr->value()->representation().IsInteger32()); + ASSERT(instr->representation().IsInteger32()); + if (instr->HasNoUses()) return NULL; + LOperand* input = UseRegisterAtStart(instr->value()); + LBitNotI* result = new(zone()) LBitNotI(input); + return DefineSameAsFirst(result); +} + + LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { if (instr->representation().IsDouble()) { return DoArithmeticD(Token::DIV, instr); @@ -1524,8 +1512,8 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) { HValue* left = instr->left(); HValue* right = instr->right(); if (instr->representation().IsSmiOrInteger32()) { - ASSERT(instr->left()->representation().Equals(instr->representation())); - ASSERT(instr->right()->representation().Equals(instr->representation())); + ASSERT(left->representation().IsSmiOrInteger32()); + ASSERT(right->representation().Equals(left->representation())); if (instr->HasPowerOf2Divisor()) { ASSERT(!right->CanBeZero()); @@ -1601,8 +1589,9 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) { LInstruction* LChunkBuilder::DoSub(HSub* instr) { if (instr->representation().IsSmiOrInteger32()) { - ASSERT(instr->left()->representation().Equals(instr->representation())); - ASSERT(instr->right()->representation().Equals(instr->representation())); + ASSERT(instr->left()->representation().IsSmiOrInteger32()); + ASSERT(instr->right()->representation().Equals( + instr->left()->representation())); LOperand* left = UseRegisterAtStart(instr->left()); LOperand* right = UseOrConstantAtStart(instr->right()); LSubI* sub = new(zone()) LSubI(left, right); @@ -1622,8 +1611,9 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) { LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { if (instr->representation().IsSmiOrInteger32()) { - ASSERT(instr->left()->representation().Equals(instr->representation())); - ASSERT(instr->right()->representation().Equals(instr->representation())); + ASSERT(instr->left()->representation().IsSmiOrInteger32()); + ASSERT(instr->right()->representation().Equals( + instr->left()->representation())); // Check to see if it would be advantageous to use an lea instruction rather // than an add. This is the case when no overflow check is needed and there // are multiple uses of the add's inputs, so using a 3-register add will @@ -1656,8 +1646,9 @@ LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) { LOperand* left = NULL; LOperand* right = NULL; if (instr->representation().IsSmiOrInteger32()) { - ASSERT(instr->left()->representation().Equals(instr->representation())); - ASSERT(instr->right()->representation().Equals(instr->representation())); + ASSERT(instr->left()->representation().IsSmiOrInteger32()); + ASSERT(instr->right()->representation().Equals( + instr->left()->representation())); left = UseRegisterAtStart(instr->BetterLeftOperand()); right = UseOrConstantAtStart(instr->BetterRightOperand()); } else { @@ -1712,8 +1703,9 @@ LInstruction* LChunkBuilder::DoCompareNumericAndBranch( HCompareNumericAndBranch* instr) { Representation r = instr->representation(); if (r.IsSmiOrInteger32()) { - ASSERT(instr->left()->representation().Equals(r)); - ASSERT(instr->right()->representation().Equals(r)); + ASSERT(instr->left()->representation().IsSmiOrInteger32()); + ASSERT(instr->left()->representation().Equals( + instr->right()->representation())); LOperand* left = UseRegisterOrConstantAtStart(instr->left()); LOperand* right = UseOrConstantAtStart(instr->right()); return new(zone()) LCompareNumericAndBranch(left, right); @@ -1743,13 +1735,6 @@ LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch( } -LInstruction* LChunkBuilder::DoCompareHoleAndBranch( - HCompareHoleAndBranch* instr) { - LOperand* object = UseRegisterAtStart(instr->object()); - return new(zone()) LCmpHoleAndBranch(object); -} - - LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) { ASSERT(instr->value()->representation().IsSmiOrTagged()); LOperand* temp = TempRegister(); @@ -1866,6 +1851,17 @@ LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) { } +LInstruction* LChunkBuilder::DoNumericConstraint(HNumericConstraint* instr) { + return NULL; +} + + +LInstruction* LChunkBuilder::DoInductionVariableAnnotation( + HInductionVariableAnnotation* instr) { + return NULL; +} + + LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { return AssignEnvironment(new(zone()) LBoundsCheck( UseRegisterOrConstantAtStart(instr->index()), @@ -2053,6 +2049,15 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { } +LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) { + LUnallocated* temp = NULL; + if (!instr->CanOmitPrototypeChecks()) temp = TempRegister(); + LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp); + if (instr->CanOmitPrototypeChecks()) return result; + return AssignEnvironment(result); +} + + LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { // If the target is in new space, we'll emit a global cell compare and so // want the value in a register. If the target gets promoted before we @@ -2066,16 +2071,10 @@ LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) { LOperand* value = NULL; - if (!instr->CanOmitMapChecks()) { - value = UseRegisterAtStart(instr->value()); - if (instr->has_migration_target()) info()->MarkAsDeferredCalling(); - } + if (!instr->CanOmitMapChecks()) value = UseRegisterAtStart(instr->value()); LCheckMaps* result = new(zone()) LCheckMaps(value); - if (!instr->CanOmitMapChecks()) { - AssignEnvironment(result); - if (instr->has_migration_target()) return AssignPointerMap(result); - } - return result; + if (instr->CanOmitMapChecks()) return result; + return AssignEnvironment(result); } @@ -2207,6 +2206,25 @@ LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) { } +LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic( + HLoadNamedFieldPolymorphic* instr) { + ASSERT(instr->representation().IsTagged()); + if (instr->need_generic()) { + LOperand* context = UseFixed(instr->context(), esi); + LOperand* obj = UseFixed(instr->object(), edx); + LLoadNamedFieldPolymorphic* result = + new(zone()) LLoadNamedFieldPolymorphic(context, obj); + return MarkAsCall(DefineFixed(result, eax), instr); + } else { + LOperand* context = UseAny(instr->context()); // Not actually used. + LOperand* obj = UseRegisterAtStart(instr->object()); + LLoadNamedFieldPolymorphic* result = + new(zone()) LLoadNamedFieldPolymorphic(context, obj); + return AssignEnvironment(DefineAsRegister(result)); + } +} + + LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { LOperand* context = UseFixed(instr->context(), esi); LOperand* object = UseFixed(instr->object(), edx); @@ -2400,7 +2418,7 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) { bool is_external_location = instr->access().IsExternalMemory() && instr->access().offset() == 0; bool needs_write_barrier = instr->NeedsWriteBarrier(); - bool needs_write_barrier_for_map = instr->has_transition() && + bool needs_write_barrier_for_map = !instr->transition().is_null() && instr->NeedsWriteBarrierForMap(); LOperand* obj; @@ -2549,7 +2567,7 @@ LInstruction* LChunkBuilder::DoParameter(HParameter* instr) { LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) { int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width. if (spill_index > LUnallocated::kMaxFixedSlotIndex) { - Abort(kTooManySpillSlotsNeededForOSR); + Abort("Too many spill slots needed for OSR"); spill_index = 0; } return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index); @@ -2573,12 +2591,6 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) { } -LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) { - // There are no real uses of a captured object. - return NULL; -} - - LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) { info()->MarkAsRequiresFrame(); LOperand* args = UseRegister(instr->arguments()); diff --git a/chromium/v8/src/ia32/lithium-ia32.h b/chromium/v8/src/ia32/lithium-ia32.h index 7ae87a08c8d..6b0f9d0a74c 100644 --- a/chromium/v8/src/ia32/lithium-ia32.h +++ b/chromium/v8/src/ia32/lithium-ia32.h @@ -50,6 +50,7 @@ class LCodeGen; V(ArithmeticD) \ V(ArithmeticT) \ V(BitI) \ + V(BitNotI) \ V(BoundsCheck) \ V(Branch) \ V(CallConstantFunction) \ @@ -67,6 +68,7 @@ class LCodeGen; V(CheckMaps) \ V(CheckMapValue) \ V(CheckNonSmi) \ + V(CheckPrototypeMaps) \ V(CheckSmi) \ V(ClampDToUint8) \ V(ClampIToUint8) \ @@ -75,7 +77,6 @@ class LCodeGen; V(ClassOfTestAndBranch) \ V(CompareNumericAndBranch) \ V(CmpObjectEqAndBranch) \ - V(CmpHoleAndBranch) \ V(CmpMapAndBranch) \ V(CmpT) \ V(ConstantD) \ @@ -128,6 +129,7 @@ class LCodeGen; V(LoadKeyed) \ V(LoadKeyedGeneric) \ V(LoadNamedField) \ + V(LoadNamedFieldPolymorphic) \ V(LoadNamedGeneric) \ V(MapEnumLength) \ V(MathAbs) \ @@ -209,10 +211,7 @@ class LInstruction: public ZoneObject { LInstruction() : environment_(NULL), hydrogen_value_(NULL), - bit_field_(IsCallBits::encode(false)) { - set_position(RelocInfo::kNoPosition); - } - + is_call_(false) { } virtual ~LInstruction() { } virtual void CompileToNative(LCodeGen* generator) = 0; @@ -251,28 +250,19 @@ class LInstruction: public ZoneObject { LPointerMap* pointer_map() const { return pointer_map_.get(); } bool HasPointerMap() const { return pointer_map_.is_set(); } - // The 31 bits PositionBits is used to store the int position value. And the - // position value may be RelocInfo::kNoPosition (-1). The accessor always - // +1/-1 so that the encoded value of position in bit_field_ is always >= 0 - // and can fit into the 31 bits PositionBits. - void set_position(int pos) { - bit_field_ = PositionBits::update(bit_field_, pos + 1); - } - int position() { return PositionBits::decode(bit_field_) - 1; } void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; } HValue* hydrogen_value() const { return hydrogen_value_; } virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { } - void MarkAsCall() { bit_field_ = IsCallBits::update(bit_field_, true); } - bool IsCall() const { return IsCallBits::decode(bit_field_); } + void MarkAsCall() { is_call_ = true; } // Interface to the register allocator and iterators. - bool ClobbersTemps() const { return IsCall(); } - bool ClobbersRegisters() const { return IsCall(); } + bool ClobbersTemps() const { return is_call_; } + bool ClobbersRegisters() const { return is_call_; } virtual bool ClobbersDoubleRegisters() const { - return IsCall() || + return is_call_ || (!CpuFeatures::IsSupported(SSE2) && // We only have rudimentary X87Stack tracking, thus in general // cannot handle deoptimization nor phi-nodes. @@ -305,13 +295,10 @@ class LInstruction: public ZoneObject { virtual int TempCount() = 0; virtual LOperand* TempAt(int i) = 0; - class IsCallBits: public BitField<bool, 0, 1> {}; - class PositionBits: public BitField<int, 1, 31> {}; - LEnvironment* environment_; SetOncePointer<LPointerMap> pointer_map_; HValue* hydrogen_value_; - int bit_field_; + bool is_call_; }; @@ -864,20 +851,8 @@ class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> { LOperand* left() { return inputs_[0]; } LOperand* right() { return inputs_[1]; } - DECLARE_CONCRETE_INSTRUCTION(CmpObjectEqAndBranch, "cmp-object-eq-and-branch") -}; - - -class LCmpHoleAndBranch: public LControlInstruction<1, 0> { - public: - explicit LCmpHoleAndBranch(LOperand* object) { - inputs_[0] = object; - } - - LOperand* object() { return inputs_[0]; } - - DECLARE_CONCRETE_INSTRUCTION(CmpHoleAndBranch, "cmp-hole-and-branch") - DECLARE_HYDROGEN_ACCESSOR(CompareHoleAndBranch) + DECLARE_CONCRETE_INSTRUCTION(CmpObjectEqAndBranch, + "cmp-object-eq-and-branch") }; @@ -1383,6 +1358,18 @@ class LThrow: public LTemplateInstruction<0, 2, 0> { }; +class LBitNotI: public LTemplateInstruction<1, 1, 0> { + public: + explicit LBitNotI(LOperand* value) { + inputs_[0] = value; + } + + LOperand* value() { return inputs_[0]; } + + DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i") +}; + + class LAddI: public LTemplateInstruction<1, 2, 0> { public: LAddI(LOperand* left, LOperand* right) { @@ -1536,6 +1523,21 @@ class LLoadNamedField: public LTemplateInstruction<1, 1, 0> { }; +class LLoadNamedFieldPolymorphic: public LTemplateInstruction<1, 2, 0> { + public: + LLoadNamedFieldPolymorphic(LOperand* context, LOperand* object) { + inputs_[0] = context; + inputs_[1] = object; + } + + LOperand* context() { return inputs_[0]; } + LOperand* object() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field-polymorphic") + DECLARE_HYDROGEN_ACCESSOR(LoadNamedFieldPolymorphic) +}; + + class LLoadNamedGeneric: public LTemplateInstruction<1, 2, 0> { public: LLoadNamedGeneric(LOperand* context, LOperand* object) { @@ -2234,7 +2236,7 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 2> { virtual void PrintDataTo(StringStream* stream); - Handle<Map> transition() const { return hydrogen()->transition_map(); } + Handle<Map> transition() const { return hydrogen()->transition(); } Representation representation() const { return hydrogen()->field_representation(); } @@ -2449,6 +2451,24 @@ class LCheckMaps: public LTemplateInstruction<0, 1, 0> { }; +class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 1> { + public: + explicit LCheckPrototypeMaps(LOperand* temp) { + temps_[0] = temp; + } + + LOperand* temp() { return temps_[0]; } + + DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps") + DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps) + + ZoneList<Handle<JSObject> >* prototypes() const { + return hydrogen()->prototypes(); + } + ZoneList<Handle<Map> >* maps() const { return hydrogen()->maps(); } +}; + + class LCheckSmi: public LTemplateInstruction<1, 1, 0> { public: explicit LCheckSmi(LOperand* value) { @@ -2780,7 +2800,7 @@ class LChunkBuilder BASE_EMBEDDED { bool is_done() const { return status_ == DONE; } bool is_aborted() const { return status_ == ABORTED; } - void Abort(BailoutReason reason); + void Abort(const char* reason); // Methods for getting operands for Use / Define / Temp. LUnallocated* ToUnallocated(Register reg); @@ -2869,8 +2889,7 @@ class LChunkBuilder BASE_EMBEDDED { CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY); LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, - int* argument_index_accumulator, - ZoneList<HValue*>* objects_to_materialize); + int* argument_index_accumulator); void VisitInstruction(HInstruction* current); diff --git a/chromium/v8/src/ia32/macro-assembler-ia32.cc b/chromium/v8/src/ia32/macro-assembler-ia32.cc index 67a7c0d2b49..2ab5a259321 100644 --- a/chromium/v8/src/ia32/macro-assembler-ia32.cc +++ b/chromium/v8/src/ia32/macro-assembler-ia32.cc @@ -54,60 +54,6 @@ MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size) } -void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) { - if (isolate()->heap()->RootCanBeTreatedAsConstant(index)) { - Handle<Object> value(&isolate()->heap()->roots_array_start()[index]); - mov(destination, value); - return; - } - ExternalReference roots_array_start = - ExternalReference::roots_array_start(isolate()); - mov(destination, Immediate(index)); - mov(destination, Operand::StaticArray(destination, - times_pointer_size, - roots_array_start)); -} - - -void MacroAssembler::StoreRoot(Register source, - Register scratch, - Heap::RootListIndex index) { - ASSERT(Heap::RootCanBeWrittenAfterInitialization(index)); - ExternalReference roots_array_start = - ExternalReference::roots_array_start(isolate()); - mov(scratch, Immediate(index)); - mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start), - source); -} - - -void MacroAssembler::CompareRoot(Register with, - Register scratch, - Heap::RootListIndex index) { - ExternalReference roots_array_start = - ExternalReference::roots_array_start(isolate()); - mov(scratch, Immediate(index)); - cmp(with, Operand::StaticArray(scratch, - times_pointer_size, - roots_array_start)); -} - - -void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) { - ASSERT(isolate()->heap()->RootCanBeTreatedAsConstant(index)); - Handle<Object> value(&isolate()->heap()->roots_array_start()[index]); - cmp(with, value); -} - - -void MacroAssembler::CompareRoot(const Operand& with, - Heap::RootListIndex index) { - ASSERT(isolate()->heap()->RootCanBeTreatedAsConstant(index)); - Handle<Object> value(&isolate()->heap()->roots_array_start()[index]); - cmp(with, value); -} - - void MacroAssembler::InNewSpace( Register object, Register scratch, @@ -486,6 +432,21 @@ void MacroAssembler::SafePush(const Immediate& x) { } +void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) { + // see ROOT_ACCESSOR macro in factory.h + Handle<Object> value(&isolate()->heap()->roots_array_start()[index]); + cmp(with, value); +} + + +void MacroAssembler::CompareRoot(const Operand& with, + Heap::RootListIndex index) { + // see ROOT_ACCESSOR macro in factory.h + Handle<Object> value(&isolate()->heap()->roots_array_start()[index]); + cmp(with, value); +} + + void MacroAssembler::CmpObjectType(Register heap_object, InstanceType type, Register map) { @@ -717,7 +678,7 @@ void MacroAssembler::AssertNumber(Register object) { JumpIfSmi(object, &ok); cmp(FieldOperand(object, HeapObject::kMapOffset), isolate()->factory()->heap_number_map()); - Check(equal, kOperandNotANumber); + Check(equal, "Operand not a number"); bind(&ok); } } @@ -726,7 +687,7 @@ void MacroAssembler::AssertNumber(Register object) { void MacroAssembler::AssertSmi(Register object) { if (emit_debug_code()) { test(object, Immediate(kSmiTagMask)); - Check(equal, kOperandIsNotASmi); + Check(equal, "Operand is not a smi"); } } @@ -734,12 +695,12 @@ void MacroAssembler::AssertSmi(Register object) { void MacroAssembler::AssertString(Register object) { if (emit_debug_code()) { test(object, Immediate(kSmiTagMask)); - Check(not_equal, kOperandIsASmiAndNotAString); + Check(not_equal, "Operand is a smi and not a string"); push(object); mov(object, FieldOperand(object, HeapObject::kMapOffset)); CmpInstanceType(object, FIRST_NONSTRING_TYPE); pop(object); - Check(below, kOperandIsNotAString); + Check(below, "Operand is not a string"); } } @@ -747,12 +708,12 @@ void MacroAssembler::AssertString(Register object) { void MacroAssembler::AssertName(Register object) { if (emit_debug_code()) { test(object, Immediate(kSmiTagMask)); - Check(not_equal, kOperandIsASmiAndNotAName); + Check(not_equal, "Operand is a smi and not a name"); push(object); mov(object, FieldOperand(object, HeapObject::kMapOffset)); CmpInstanceType(object, LAST_NAME_TYPE); pop(object); - Check(below_equal, kOperandIsNotAName); + Check(below_equal, "Operand is not a name"); } } @@ -760,7 +721,7 @@ void MacroAssembler::AssertName(Register object) { void MacroAssembler::AssertNotSmi(Register object) { if (emit_debug_code()) { test(object, Immediate(kSmiTagMask)); - Check(not_equal, kOperandIsASmi); + Check(not_equal, "Operand is a smi"); } } @@ -773,7 +734,7 @@ void MacroAssembler::EnterFrame(StackFrame::Type type) { push(Immediate(CodeObject())); if (emit_debug_code()) { cmp(Operand(esp, 0), Immediate(isolate()->factory()->undefined_value())); - Check(not_equal, kCodeObjectNotProperlyPatched); + Check(not_equal, "code object not properly patched"); } } @@ -782,7 +743,7 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) { if (emit_debug_code()) { cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset), Immediate(Smi::FromInt(type))); - Check(equal, kStackFrameTypesMustMatch); + Check(equal, "stack frame types must match"); } leave(); } @@ -1063,7 +1024,7 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, // When generating debug code, make sure the lexical context is set. if (emit_debug_code()) { cmp(scratch1, Immediate(0)); - Check(not_equal, kWeShouldNotHaveAnEmptyLexicalContext); + Check(not_equal, "we should not have an empty lexical context"); } // Load the native context of the current context. int offset = @@ -1076,7 +1037,7 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, // Read the first word and compare to native_context_map. cmp(FieldOperand(scratch1, HeapObject::kMapOffset), isolate()->factory()->native_context_map()); - Check(equal, kJSGlobalObjectNativeContextShouldBeANativeContext); + Check(equal, "JSGlobalObject::native_context should be a native context."); } // Check if both contexts are the same. @@ -1095,12 +1056,12 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, // Check the context is a native context. if (emit_debug_code()) { cmp(scratch2, isolate()->factory()->null_value()); - Check(not_equal, kJSGlobalProxyContextShouldNotBeNull); + Check(not_equal, "JSGlobalProxy::context() should not be null."); // Read the first word and compare to native_context_map(), cmp(FieldOperand(scratch2, HeapObject::kMapOffset), isolate()->factory()->native_context_map()); - Check(equal, kJSGlobalObjectNativeContextShouldBeANativeContext); + Check(equal, "JSGlobalObject::native_context should be a native context."); } int token_offset = Context::kHeaderSize + @@ -1245,7 +1206,7 @@ void MacroAssembler::LoadAllocationTopHelper(Register result, #ifdef DEBUG // Assert that result actually contains top on entry. cmp(result, Operand::StaticVariable(allocation_top)); - Check(equal, kUnexpectedAllocationTop); + Check(equal, "Unexpected allocation top"); #endif return; } @@ -1265,7 +1226,7 @@ void MacroAssembler::UpdateAllocationTopHelper(Register result_end, AllocationFlags flags) { if (emit_debug_code()) { test(result_end, Immediate(kObjectAlignmentMask)); - Check(zero, kUnalignedAllocationInNewSpace); + Check(zero, "Unaligned allocation in new space"); } ExternalReference allocation_top = @@ -1497,7 +1458,7 @@ void MacroAssembler::UndoAllocationInNewSpace(Register object) { and_(object, Immediate(~kHeapObjectTagMask)); #ifdef DEBUG cmp(object, Operand::StaticVariable(new_space_allocation_top)); - Check(below, kUndoAllocationOfNonAllocatedMemory); + Check(below, "Undo allocation of non allocated memory"); #endif mov(Operand::StaticVariable(new_space_allocation_top), object); } @@ -2101,7 +2062,7 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address, // previous handle scope. mov(Operand::StaticVariable(next_address), ebx); sub(Operand::StaticVariable(level_address), Immediate(1)); - Assert(above_equal, kInvalidHandleScopeLevel); + Assert(above_equal, "Invalid HandleScope level"); cmp(edi, Operand::StaticVariable(limit_address)); j(not_equal, &delete_allocated_handles); bind(&leave_exit_frame); @@ -2143,7 +2104,7 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address, cmp(return_value, isolate()->factory()->null_value()); j(equal, &ok, Label::kNear); - Abort(kAPICallReturnedInvalidObject); + Abort("API call returned invalid object"); bind(&ok); #endif @@ -2429,7 +2390,7 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) { if (emit_debug_code()) { cmp(FieldOperand(dst, HeapObject::kMapOffset), isolate()->factory()->with_context_map()); - Check(not_equal, kVariableResolvedToWithContext); + Check(not_equal, "Variable resolved to with context."); } } @@ -2516,7 +2477,7 @@ void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, CheckMap(map, isolate()->factory()->meta_map(), &fail, DO_SMI_CHECK); jmp(&ok); bind(&fail); - Abort(kGlobalFunctionsMustHaveInitialMap); + Abort("Global functions must have initial map"); bind(&ok); } } @@ -2617,7 +2578,7 @@ void MacroAssembler::VerifyX87StackDepth(uint32_t depth) { and_(eax, kTopMask); shr(eax, 11); cmp(eax, Immediate(tos)); - Check(equal, kUnexpectedFPUStackDepthAfterInstruction); + Check(equal, "Unexpected FPU stack depth after instruction"); fnclex(); pop(eax); } @@ -2700,8 +2661,8 @@ void MacroAssembler::DecrementCounter(Condition cc, } -void MacroAssembler::Assert(Condition cc, BailoutReason reason) { - if (emit_debug_code()) Check(cc, reason); +void MacroAssembler::Assert(Condition cc, const char* msg) { + if (emit_debug_code()) Check(cc, msg); } @@ -2718,16 +2679,16 @@ void MacroAssembler::AssertFastElements(Register elements) { cmp(FieldOperand(elements, HeapObject::kMapOffset), Immediate(factory->fixed_cow_array_map())); j(equal, &ok); - Abort(kJSObjectWithFastElementsMapHasSlowElements); + Abort("JSObject with fast elements map has slow elements"); bind(&ok); } } -void MacroAssembler::Check(Condition cc, BailoutReason reason) { +void MacroAssembler::Check(Condition cc, const char* msg) { Label L; j(cc, &L); - Abort(reason); + Abort(msg); // will not return here bind(&L); } @@ -2748,13 +2709,12 @@ void MacroAssembler::CheckStackAlignment() { } -void MacroAssembler::Abort(BailoutReason reason) { +void MacroAssembler::Abort(const char* msg) { // We want to pass the msg string like a smi to avoid GC // problems, however msg is not guaranteed to be aligned // properly. Instead, we pass an aligned pointer that is // a proper v8 smi, but also pass the alignment difference // from the real pointer as a smi. - const char* msg = GetBailoutReason(reason); intptr_t p1 = reinterpret_cast<intptr_t>(msg); intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag; ASSERT(reinterpret_cast<Object*>(p0)->IsSmi()); @@ -3158,7 +3118,7 @@ void MacroAssembler::EnsureNotWhite( if (emit_debug_code()) { mov(length, Operand(bitmap_scratch, MemoryChunk::kLiveBytesOffset)); cmp(length, Operand(bitmap_scratch, MemoryChunk::kSizeOffset)); - Check(less_equal, kLiveBytesCountOverflowChunkSize); + Check(less_equal, "Live Bytes Count overflow chunk size"); } bind(&done); diff --git a/chromium/v8/src/ia32/macro-assembler-ia32.h b/chromium/v8/src/ia32/macro-assembler-ia32.h index d537b0b2cbd..3bca930d667 100644 --- a/chromium/v8/src/ia32/macro-assembler-ia32.h +++ b/chromium/v8/src/ia32/macro-assembler-ia32.h @@ -61,15 +61,6 @@ class MacroAssembler: public Assembler { // macro assembler. MacroAssembler(Isolate* isolate, void* buffer, int size); - // Operations on roots in the root-array. - void LoadRoot(Register destination, Heap::RootListIndex index); - void StoreRoot(Register source, Register scratch, Heap::RootListIndex index); - void CompareRoot(Register with, Register scratch, Heap::RootListIndex index); - // These methods can only be used with constant roots (i.e. non-writable - // and not in new space). - void CompareRoot(Register with, Heap::RootListIndex index); - void CompareRoot(const Operand& with, Heap::RootListIndex index); - // --------------------------------------------------------------------------- // GC Support enum RememberedSetFinalAction { @@ -371,6 +362,10 @@ class MacroAssembler: public Assembler { void SafeSet(Register dst, const Immediate& x); void SafePush(const Immediate& x); + // Compare against a known root, e.g. undefined, null, true, ... + void CompareRoot(Register with, Heap::RootListIndex index); + void CompareRoot(const Operand& with, Heap::RootListIndex index); + // 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); @@ -812,8 +807,6 @@ class MacroAssembler: public Assembler { void Drop(int element_count); void Call(Label* target) { call(target); } - void Push(Register src) { push(src); } - void Pop(Register dst) { pop(dst); } // Emit call to the code we are currently generating. void CallSelf() { @@ -851,15 +844,15 @@ class MacroAssembler: public Assembler { // Calls Abort(msg) if the condition cc is not satisfied. // Use --debug_code to enable. - void Assert(Condition cc, BailoutReason reason); + void Assert(Condition cc, const char* msg); void AssertFastElements(Register elements); // Like Assert(), but always enabled. - void Check(Condition cc, BailoutReason reason); + void Check(Condition cc, const char* msg); // Print a message to stdout and abort execution. - void Abort(BailoutReason reason); + void Abort(const char* msg); // Check that the stack is aligned. void CheckStackAlignment(); diff --git a/chromium/v8/src/ia32/stub-cache-ia32.cc b/chromium/v8/src/ia32/stub-cache-ia32.cc index df7ad4467f9..123506fa623 100644 --- a/chromium/v8/src/ia32/stub-cache-ia32.cc +++ b/chromium/v8/src/ia32/stub-cache-ia32.cc @@ -2479,8 +2479,6 @@ Handle<Code> CallStubCompiler::CompileMathAbsCall( STATIC_ASSERT(kSmiTag == 0); __ JumpIfNotSmi(eax, ¬_smi); - // Branchless abs implementation, refer to below: - // http://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0 // otherwise. __ mov(ebx, eax); @@ -3155,7 +3153,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal( __ j(equal, &miss); } else if (FLAG_debug_code) { __ cmp(eax, factory()->the_hole_value()); - __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); + __ Check(not_equal, "DontDelete cells can't contain the hole"); } HandlerFrontendFooter(name, &success, &miss); diff --git a/chromium/v8/src/ic.cc b/chromium/v8/src/ic.cc index 3c22580c2c7..a55160a394e 100644 --- a/chromium/v8/src/ic.cc +++ b/chromium/v8/src/ic.cc @@ -390,6 +390,7 @@ void IC::Clear(Address address) { case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target); case Code::COMPARE_IC: return CompareIC::Clear(address, target); case Code::COMPARE_NIL_IC: return CompareNilIC::Clear(address, target); + case Code::UNARY_OP_IC: case Code::BINARY_OP_IC: case Code::TO_BOOLEAN_IC: // Clearing these is tricky and does not @@ -2588,6 +2589,27 @@ void BinaryOpIC::StubInfoToType(int minor_key, } +MaybeObject* UnaryOpIC::Transition(Handle<Object> object) { + Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state(); + UnaryOpStub stub(extra_ic_state); + + stub.UpdateStatus(object); + + Handle<Code> code = stub.GetCode(isolate()); + set_target(*code); + + return stub.Result(object, isolate()); +} + + +RUNTIME_FUNCTION(MaybeObject*, UnaryOpIC_Miss) { + HandleScope scope(isolate); + Handle<Object> object = args.at<Object>(0); + UnaryOpIC ic(isolate); + return ic.Transition(object); +} + + static BinaryOpIC::TypeInfo TypeInfoFromValue(Handle<Object> value, Token::Value op) { v8::internal::TypeInfo type = v8::internal::TypeInfo::FromValue(value); diff --git a/chromium/v8/src/ic.h b/chromium/v8/src/ic.h index fcf0de58f1a..7820d407ec1 100644 --- a/chromium/v8/src/ic.h +++ b/chromium/v8/src/ic.h @@ -714,6 +714,14 @@ class KeyedStoreIC: public StoreIC { }; +class UnaryOpIC: public IC { + public: + explicit UnaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { } + + MUST_USE_RESULT MaybeObject* Transition(Handle<Object> object); +}; + + // Type Recording BinaryOpIC, that records the types of the inputs and outputs. class BinaryOpIC: public IC { public: diff --git a/chromium/v8/src/isolate.cc b/chromium/v8/src/isolate.cc index 7b77d893f15..61f1e2dcfa5 100644 --- a/chromium/v8/src/isolate.cc +++ b/chromium/v8/src/isolate.cc @@ -1774,7 +1774,6 @@ Isolate::Isolate() inner_pointer_to_code_cache_(NULL), write_iterator_(NULL), global_handles_(NULL), - eternal_handles_(NULL), context_switcher_(NULL), thread_manager_(NULL), fp_stubs_generated_(false), @@ -1783,6 +1782,7 @@ Isolate::Isolate() regexp_stack_(NULL), date_cache_(NULL), code_stub_interface_descriptors_(NULL), + context_exit_happened_(false), initialized_from_snapshot_(false), cpu_profiler_(NULL), heap_profiler_(NULL), @@ -2052,8 +2052,6 @@ Isolate::~Isolate() { code_range_ = NULL; delete global_handles_; global_handles_ = NULL; - delete eternal_handles_; - eternal_handles_ = NULL; delete string_stream_debug_object_cache_; string_stream_debug_object_cache_ = NULL; @@ -2185,7 +2183,6 @@ bool Isolate::Init(Deserializer* des) { inner_pointer_to_code_cache_ = new InnerPointerToCodeCache(this); write_iterator_ = new ConsStringIteratorOp(); global_handles_ = new GlobalHandles(this); - eternal_handles_ = new EternalHandles(); bootstrapper_ = new Bootstrapper(this); handle_scope_implementer_ = new HandleScopeImplementer(this); stub_cache_ = new StubCache(this); diff --git a/chromium/v8/src/isolate.h b/chromium/v8/src/isolate.h index 401505afdda..c0083177373 100644 --- a/chromium/v8/src/isolate.h +++ b/chromium/v8/src/isolate.h @@ -661,9 +661,9 @@ class Isolate { } inline Address* handler_address() { return &thread_local_top_.handler_; } - // Bottom JS entry. - Address js_entry_sp() { - return thread_local_top_.js_entry_sp_; + // Bottom JS entry (see StackTracer::Trace in sampler.cc). + static Address js_entry_sp(ThreadLocalTop* thread) { + return thread->js_entry_sp_; } inline Address* js_entry_sp_address() { return &thread_local_top_.js_entry_sp_; @@ -922,8 +922,6 @@ class Isolate { GlobalHandles* global_handles() { return global_handles_; } - EternalHandles* eternal_handles() { return eternal_handles_; } - ThreadManager* thread_manager() { return thread_manager_; } ContextSwitcher* context_switcher() { return context_switcher_; } @@ -1062,6 +1060,13 @@ class Isolate { thread_local_top_.top_lookup_result_ = top; } + bool context_exit_happened() { + return context_exit_happened_; + } + void set_context_exit_happened(bool context_exit_happened) { + context_exit_happened_ = context_exit_happened; + } + bool initialized_from_snapshot() { return initialized_from_snapshot_; } double time_millis_since_init() { @@ -1290,7 +1295,6 @@ class Isolate { InnerPointerToCodeCache* inner_pointer_to_code_cache_; ConsStringIteratorOp* write_iterator_; GlobalHandles* global_handles_; - EternalHandles* eternal_handles_; ContextSwitcher* context_switcher_; ThreadManager* thread_manager_; RuntimeState runtime_state_; @@ -1310,6 +1314,10 @@ class Isolate { unibrow::Mapping<unibrow::Ecma262Canonicalize> interp_canonicalize_mapping_; CodeStubInterfaceDescriptor* code_stub_interface_descriptors_; + // The garbage collector should be a little more aggressive when it knows + // that a context was recently exited. + bool context_exit_happened_; + // True if this isolate was initialized from a snapshot. bool initialized_from_snapshot_; diff --git a/chromium/v8/src/lithium.cc b/chromium/v8/src/lithium.cc index 790a2182b17..e9c3531e385 100644 --- a/chromium/v8/src/lithium.cc +++ b/chromium/v8/src/lithium.cc @@ -425,7 +425,7 @@ LChunk* LChunk::NewChunk(HGraph* graph) { int values = graph->GetMaximumValueID(); CompilationInfo* info = graph->info(); if (values > LUnallocated::kMaxVirtualRegisters) { - info->set_bailout_reason(kNotEnoughVirtualRegistersForValues); + info->set_bailout_reason("not enough virtual registers for values"); return NULL; } LAllocator allocator(values, graph); @@ -434,7 +434,7 @@ LChunk* LChunk::NewChunk(HGraph* graph) { if (chunk == NULL) return NULL; if (!allocator.Allocate(chunk)) { - info->set_bailout_reason(kNotEnoughVirtualRegistersRegalloc); + info->set_bailout_reason("not enough virtual registers (regalloc)"); return NULL; } diff --git a/chromium/v8/src/lithium.h b/chromium/v8/src/lithium.h index f773916485d..1e0784eb98d 100644 --- a/chromium/v8/src/lithium.h +++ b/chromium/v8/src/lithium.h @@ -533,7 +533,6 @@ class LEnvironment: public ZoneObject { values_(value_count, zone), is_tagged_(value_count, zone), is_uint32_(value_count, zone), - object_mapping_(0, zone), outer_(outer), entry_(entry), zone_(zone) { } @@ -574,38 +573,6 @@ class LEnvironment: public ZoneObject { return is_uint32_.Contains(index); } - void AddNewObject(int length, bool is_arguments) { - uint32_t encoded = LengthOrDupeField::encode(length) | - IsArgumentsField::encode(is_arguments) | - IsDuplicateField::encode(false); - object_mapping_.Add(encoded, zone()); - } - - void AddDuplicateObject(int dupe_of) { - uint32_t encoded = LengthOrDupeField::encode(dupe_of) | - IsDuplicateField::encode(true); - object_mapping_.Add(encoded, zone()); - } - - int ObjectDuplicateOfAt(int index) { - ASSERT(ObjectIsDuplicateAt(index)); - return LengthOrDupeField::decode(object_mapping_[index]); - } - - int ObjectLengthAt(int index) { - ASSERT(!ObjectIsDuplicateAt(index)); - return LengthOrDupeField::decode(object_mapping_[index]); - } - - bool ObjectIsArgumentsAt(int index) { - ASSERT(!ObjectIsDuplicateAt(index)); - return IsArgumentsField::decode(object_mapping_[index]); - } - - bool ObjectIsDuplicateAt(int index) { - return IsDuplicateField::decode(object_mapping_[index]); - } - void Register(int deoptimization_index, int translation_index, int pc_offset) { @@ -620,14 +587,6 @@ class LEnvironment: public ZoneObject { void PrintTo(StringStream* stream); - // Marker value indicating a de-materialized object. - static LOperand* materialization_marker() { return NULL; } - - // Encoding used for the object_mapping map below. - class LengthOrDupeField : public BitField<int, 0, 30> { }; - class IsArgumentsField : public BitField<bool, 30, 1> { }; - class IsDuplicateField : public BitField<bool, 31, 1> { }; - private: Handle<JSFunction> closure_; FrameType frame_type_; @@ -644,10 +603,6 @@ class LEnvironment: public ZoneObject { ZoneList<LOperand*> values_; GrowableBitVector is_tagged_; GrowableBitVector is_uint32_; - - // Map with encoded information about materialization_marker operands. - ZoneList<uint32_t> object_mapping_; - LEnvironment* outer_; HEnterInlined* entry_; Zone* zone_; @@ -799,7 +754,8 @@ int StackSlotOffset(int index); enum NumberUntagDMode { NUMBER_CANDIDATE_IS_SMI, - NUMBER_CANDIDATE_IS_ANY_TAGGED + NUMBER_CANDIDATE_IS_ANY_TAGGED, + NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE }; diff --git a/chromium/v8/src/liveedit.cc b/chromium/v8/src/liveedit.cc index 406510a3b86..859cf2b94f3 100644 --- a/chromium/v8/src/liveedit.cc +++ b/chromium/v8/src/liveedit.cc @@ -1290,7 +1290,6 @@ MaybeObject* LiveEdit::ReplaceFunctionCode( if (code_scope_info->IsFixedArray()) { shared_info->set_scope_info(ScopeInfo::cast(*code_scope_info)); } - shared_info->DisableOptimization(kLiveEdit); } if (shared_info->debug_info()->IsDebugInfo()) { diff --git a/chromium/v8/src/log.cc b/chromium/v8/src/log.cc index a1e5a6752b1..b89c2bfba01 100644 --- a/chromium/v8/src/log.cc +++ b/chromium/v8/src/log.cc @@ -1644,6 +1644,7 @@ void Logger::LogCodeObject(Object* object) { case Code::FUNCTION: case Code::OPTIMIZED_FUNCTION: return; // We log this later using LogCompiledFunctions. + case Code::UNARY_OP_IC: // fall through case Code::BINARY_OP_IC: // fall through case Code::COMPARE_IC: // fall through case Code::COMPARE_NIL_IC: // fall through diff --git a/chromium/v8/src/mark-compact.cc b/chromium/v8/src/mark-compact.cc index 0e842670280..91da8a0117a 100644 --- a/chromium/v8/src/mark-compact.cc +++ b/chromium/v8/src/mark-compact.cc @@ -431,8 +431,8 @@ void MarkCompactCollector::CollectGarbage() { heap()->weak_embedded_maps_verification_enabled()) { VerifyWeakEmbeddedMapsInOptimizedCode(); } - if (FLAG_collect_maps && FLAG_omit_map_checks_for_leaf_maps) { - VerifyOmittedMapChecks(); + if (FLAG_collect_maps && FLAG_omit_prototype_checks_for_leaf_maps) { + VerifyOmittedPrototypeChecks(); } #endif @@ -503,13 +503,13 @@ void MarkCompactCollector::VerifyWeakEmbeddedMapsInOptimizedCode() { } -void MarkCompactCollector::VerifyOmittedMapChecks() { +void MarkCompactCollector::VerifyOmittedPrototypeChecks() { HeapObjectIterator iterator(heap()->map_space()); for (HeapObject* obj = iterator.Next(); obj != NULL; obj = iterator.Next()) { Map* map = Map::cast(obj); - map->VerifyOmittedMapChecks(); + map->VerifyOmittedPrototypeChecks(); } } #endif // VERIFY_HEAP diff --git a/chromium/v8/src/mark-compact.h b/chromium/v8/src/mark-compact.h index ee845a08370..16e49e10295 100644 --- a/chromium/v8/src/mark-compact.h +++ b/chromium/v8/src/mark-compact.h @@ -638,7 +638,7 @@ class MarkCompactCollector { static void VerifyMarkbitsAreClean(PagedSpace* space); static void VerifyMarkbitsAreClean(NewSpace* space); void VerifyWeakEmbeddedMapsInOptimizedCode(); - void VerifyOmittedMapChecks(); + void VerifyOmittedPrototypeChecks(); #endif // Sweep a single page from the given space conservatively. diff --git a/chromium/v8/src/messages.js b/chromium/v8/src/messages.js index 2debbf86540..b586d24882b 100644 --- a/chromium/v8/src/messages.js +++ b/chromium/v8/src/messages.js @@ -228,18 +228,16 @@ function NoSideEffectToString(obj) { } } } - if (CanBeSafelyTreatedAsAnErrorObject(obj)) { - return %_CallFunction(obj, ErrorToString); - } + if (IsNativeErrorObject(obj)) return %_CallFunction(obj, ErrorToString); return %_CallFunction(obj, ObjectToString); } -// To determine whether we can safely stringify an object using ErrorToString -// without the risk of side-effects, we need to check whether the object is -// either an instance of a native error type (via '%_ClassOf'), or has $Error -// in its prototype chain and hasn't overwritten 'toString' with something -// strange and unusual. -function CanBeSafelyTreatedAsAnErrorObject(obj) { + +// To check if something is a native error we need to check the +// concrete native error types. It is not sufficient to use instanceof +// since it possible to create an object that has Error.prototype on +// its prototype chain. This is the case for DOMException for example. +function IsNativeErrorObject(obj) { switch (%_ClassOf(obj)) { case 'Error': case 'EvalError': @@ -250,9 +248,7 @@ function CanBeSafelyTreatedAsAnErrorObject(obj) { case 'URIError': return true; } - - var objToString = %GetDataProperty(obj, "toString"); - return obj instanceof $Error && objToString === ErrorToString; + return false; } @@ -261,7 +257,7 @@ function CanBeSafelyTreatedAsAnErrorObject(obj) { // the error to string method. This is to avoid leaking error // objects between script tags in a browser setting. function ToStringCheckErrorObject(obj) { - if (CanBeSafelyTreatedAsAnErrorObject(obj)) { + if (IsNativeErrorObject(obj)) { return %_CallFunction(obj, ErrorToString); } else { return ToString(obj); diff --git a/chromium/v8/src/mips/assembler-mips.h b/chromium/v8/src/mips/assembler-mips.h index cb0896a8ded..8d533b36f40 100644 --- a/chromium/v8/src/mips/assembler-mips.h +++ b/chromium/v8/src/mips/assembler-mips.h @@ -358,11 +358,6 @@ class Operand BASE_EMBEDDED { // Return true if this is a register operand. INLINE(bool is_reg() const); - inline int32_t immediate() const { - ASSERT(!is_reg()); - return imm32_; - } - Register rm() const { return rm_; } private: diff --git a/chromium/v8/src/mips/builtins-mips.cc b/chromium/v8/src/mips/builtins-mips.cc index d424cbc7261..3f5dca00096 100644 --- a/chromium/v8/src/mips/builtins-mips.cc +++ b/chromium/v8/src/mips/builtins-mips.cc @@ -123,10 +123,10 @@ void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { // Initial map for the builtin InternalArray functions should be maps. __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset)); __ And(t0, a2, Operand(kSmiTagMask)); - __ Assert(ne, kUnexpectedInitialMapForInternalArrayFunction, + __ Assert(ne, "Unexpected initial map for InternalArray function", t0, Operand(zero_reg)); __ GetObjectType(a2, a3, t0); - __ Assert(eq, kUnexpectedInitialMapForInternalArrayFunction, + __ Assert(eq, "Unexpected initial map for InternalArray function", t0, Operand(MAP_TYPE)); } @@ -153,10 +153,10 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { // Initial map for the builtin Array functions should be maps. __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset)); __ And(t0, a2, Operand(kSmiTagMask)); - __ Assert(ne, kUnexpectedInitialMapForArrayFunction1, + __ Assert(ne, "Unexpected initial map for Array function (1)", t0, Operand(zero_reg)); __ GetObjectType(a2, a3, t0); - __ Assert(eq, kUnexpectedInitialMapForArrayFunction2, + __ Assert(eq, "Unexpected initial map for Array function (2)", t0, Operand(MAP_TYPE)); } @@ -185,7 +185,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { Register function = a1; if (FLAG_debug_code) { __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, a2); - __ Assert(eq, kUnexpectedStringFunction, function, Operand(a2)); + __ Assert(eq, "Unexpected String function", function, Operand(a2)); } // Load the first arguments in a0 and get rid of the rest. @@ -231,10 +231,10 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { __ LoadGlobalFunctionInitialMap(function, map, t0); if (FLAG_debug_code) { __ lbu(t0, FieldMemOperand(map, Map::kInstanceSizeOffset)); - __ Assert(eq, kUnexpectedStringWrapperInstanceSize, + __ Assert(eq, "Unexpected string wrapper instance size", t0, Operand(JSValue::kSize >> kPointerSizeLog2)); __ lbu(t0, FieldMemOperand(map, Map::kUnusedPropertyFieldsOffset)); - __ Assert(eq, kUnexpectedUnusedPropertiesOfStringWrapper, + __ Assert(eq, "Unexpected unused properties of string wrapper", t0, Operand(zero_reg)); } __ sw(map, FieldMemOperand(v0, HeapObject::kMapOffset)); @@ -489,7 +489,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, __ addu(a0, t5, t0); // a0: offset of first field after pre-allocated fields if (FLAG_debug_code) { - __ Assert(le, kUnexpectedNumberOfPreAllocatedPropertyFields, + __ Assert(le, "Unexpected number of pre-allocated property fields.", a0, Operand(t6)); } __ InitializeFieldsWithFiller(t5, a0, t7); @@ -522,7 +522,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // Done if no extra properties are to be allocated. __ Branch(&allocated, eq, a3, Operand(zero_reg)); - __ Assert(greater_equal, kPropertyAllocationCountFailed, + __ Assert(greater_equal, "Property allocation count failed.", a3, Operand(zero_reg)); // Scale the number of elements by pointer size and add the header for @@ -569,7 +569,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, __ LoadRoot(t7, Heap::kUndefinedValueRootIndex); } else if (FLAG_debug_code) { __ LoadRoot(t8, Heap::kUndefinedValueRootIndex); - __ Assert(eq, kUndefinedValueNotLoaded, t7, Operand(t8)); + __ Assert(eq, "Undefined value not loaded.", t7, Operand(t8)); } __ jmp(&entry); __ bind(&loop); diff --git a/chromium/v8/src/mips/code-stubs-mips.cc b/chromium/v8/src/mips/code-stubs-mips.cc index 8a03a9a31a5..0e1b224eadf 100644 --- a/chromium/v8/src/mips/code-stubs-mips.cc +++ b/chromium/v8/src/mips/code-stubs-mips.cc @@ -247,6 +247,17 @@ void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( } +void UnaryOpStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + static Register registers[] = { a0 }; + descriptor->register_param_count_ = 1; + descriptor->register_params_ = registers; + descriptor->deoptimization_handler_ = + FUNCTION_ADDR(UnaryOpIC_Miss); +} + + void StoreGlobalStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { @@ -509,7 +520,8 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) { Label after_sentinel; __ JumpIfNotSmi(a3, &after_sentinel); if (FLAG_debug_code) { - __ Assert(eq, kExpected0AsASmiSentinel, a3, Operand(zero_reg)); + const char* message = "Expected 0 as a Smi sentinel"; + __ Assert(eq, message, a3, Operand(zero_reg)); } __ lw(a3, GlobalObjectOperand()); __ lw(a3, FieldMemOperand(a3, GlobalObject::kNativeContextOffset)); @@ -667,7 +679,7 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm, Label* not_number) { __ AssertRootValue(heap_number_map, Heap::kHeapNumberMapRootIndex, - kHeapNumberMapRegisterClobbered); + "HeapNumberMap register clobbered."); Label is_smi, done; @@ -717,7 +729,7 @@ void FloatingPointHelper::ConvertNumberToInt32(MacroAssembler* masm, Label* not_number) { __ AssertRootValue(heap_number_map, Heap::kHeapNumberMapRootIndex, - kHeapNumberMapRegisterClobbered); + "HeapNumberMap register clobbered."); Label done; Label not_in_int32_range; @@ -794,7 +806,7 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm, __ bind(&obj_is_not_smi); __ AssertRootValue(heap_number_map, Heap::kHeapNumberMapRootIndex, - kHeapNumberMapRegisterClobbered); + "HeapNumberMap register clobbered."); __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32); // Load the number. @@ -841,7 +853,7 @@ void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm, __ AssertRootValue(heap_number_map, Heap::kHeapNumberMapRootIndex, - kHeapNumberMapRegisterClobbered); + "HeapNumberMap register clobbered."); __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, &maybe_undefined); @@ -4267,12 +4279,12 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { if (FLAG_debug_code) { __ And(t0, regexp_data, Operand(kSmiTagMask)); __ Check(nz, - kUnexpectedTypeForRegExpDataFixedArrayExpected, + "Unexpected type for RegExp data, FixedArray expected", t0, Operand(zero_reg)); __ GetObjectType(regexp_data, a0, a0); __ Check(eq, - kUnexpectedTypeForRegExpDataFixedArrayExpected, + "Unexpected type for RegExp data, FixedArray expected", a0, Operand(FIXED_ARRAY_TYPE)); } @@ -4627,7 +4639,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // Sequential strings have already been ruled out. __ And(at, a0, Operand(kIsIndirectStringMask)); __ Assert(eq, - kExternalStringExpectedButNotFound, + "external string expected, but not found", at, Operand(zero_reg)); } @@ -5008,7 +5020,7 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { void StringCharCodeAtGenerator::GenerateSlow( MacroAssembler* masm, const RuntimeCallHelper& call_helper) { - __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase); + __ Abort("Unexpected fallthrough to CharCodeAt slow case"); // Index is not a smi. __ bind(&index_not_smi_); @@ -5057,7 +5069,7 @@ void StringCharCodeAtGenerator::GenerateSlow( call_helper.AfterCall(masm); __ jmp(&exit_); - __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase); + __ Abort("Unexpected fallthrough from CharCodeAt slow case"); } @@ -5094,7 +5106,7 @@ void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { void StringCharFromCodeGenerator::GenerateSlow( MacroAssembler* masm, const RuntimeCallHelper& call_helper) { - __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase); + __ Abort("Unexpected fallthrough to CharFromCode slow case"); __ bind(&slow_case_); call_helper.BeforeCall(masm); @@ -5105,7 +5117,7 @@ void StringCharFromCodeGenerator::GenerateSlow( call_helper.AfterCall(masm); __ Branch(&exit_); - __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); + __ Abort("Unexpected fallthrough from CharFromCode slow case"); } @@ -5160,7 +5172,7 @@ void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm, // that it is. __ And(scratch4, dest, Operand(kPointerAlignmentMask)); __ Check(eq, - kDestinationOfCopyNotAligned, + "Destination of copy not aligned.", scratch4, Operand(zero_reg)); } @@ -5360,7 +5372,7 @@ void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, // Must be the hole (deleted entry). if (FLAG_debug_code) { __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); - __ Assert(eq, kOddballInStringTableIsNotUndefinedOrTheHole, + __ Assert(eq, "oddball in string table is not undefined or the hole", scratch, Operand(candidate)); } __ jmp(&next_probe[i]); @@ -6568,7 +6580,7 @@ void DirectCEntryStub::Generate(MacroAssembler* masm) { // filled with kZapValue by the GC. // Dereference the address and check for this. __ lw(t0, MemOperand(t9)); - __ Assert(ne, kReceivedInvalidReturnAddress, t0, + __ Assert(ne, "Received invalid return address.", t0, Operand(reinterpret_cast<uint32_t>(kZapValue))); } __ Jump(t9); @@ -7319,7 +7331,7 @@ static void CreateArrayDispatch(MacroAssembler* masm) { } // If we reached this point there is a problem. - __ Abort(kUnexpectedElementsKindInArrayConstructor); + __ Abort("Unexpected ElementsKind in array constructor"); } @@ -7374,7 +7386,7 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm) { } // If we reached this point there is a problem. - __ Abort(kUnexpectedElementsKindInArrayConstructor); + __ Abort("Unexpected ElementsKind in array constructor"); } @@ -7435,10 +7447,10 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) { __ lw(a3, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset)); // Will both indicate a NULL and a Smi. __ And(at, a3, Operand(kSmiTagMask)); - __ Assert(ne, kUnexpectedInitialMapForArrayFunction, + __ Assert(ne, "Unexpected initial map for Array function", at, Operand(zero_reg)); __ GetObjectType(a3, a3, t0); - __ Assert(eq, kUnexpectedInitialMapForArrayFunction, + __ Assert(eq, "Unexpected initial map for Array function", t0, Operand(MAP_TYPE)); // We should either have undefined in a2 or a valid cell. @@ -7447,7 +7459,7 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) { __ LoadRoot(at, Heap::kUndefinedValueRootIndex); __ Branch(&okay_here, eq, a2, Operand(at)); __ lw(a3, FieldMemOperand(a2, 0)); - __ Assert(eq, kExpectedPropertyCellInRegisterA2, + __ Assert(eq, "Expected property cell in register a2", a3, Operand(cell_map)); __ bind(&okay_here); } @@ -7547,10 +7559,10 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { __ lw(a3, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset)); // Will both indicate a NULL and a Smi. __ And(at, a3, Operand(kSmiTagMask)); - __ Assert(ne, kUnexpectedInitialMapForArrayFunction, + __ Assert(ne, "Unexpected initial map for Array function", at, Operand(zero_reg)); __ GetObjectType(a3, a3, t0); - __ Assert(eq, kUnexpectedInitialMapForArrayFunction, + __ Assert(eq, "Unexpected initial map for Array function", t0, Operand(MAP_TYPE)); } @@ -7567,7 +7579,7 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { Label done; __ Branch(&done, eq, a3, Operand(FAST_ELEMENTS)); __ Assert( - eq, kInvalidElementsKindForInternalArrayOrInternalPackedArray, + eq, "Invalid ElementsKind for InternalArray or InternalPackedArray", a3, Operand(FAST_HOLEY_ELEMENTS)); __ bind(&done); } diff --git a/chromium/v8/src/mips/codegen-mips.cc b/chromium/v8/src/mips/codegen-mips.cc index 5c847fc8f62..3f74154f58a 100644 --- a/chromium/v8/src/mips/codegen-mips.cc +++ b/chromium/v8/src/mips/codegen-mips.cc @@ -205,7 +205,7 @@ void ElementsTransitionGenerator::GenerateSmiToDouble( // Allocate new FixedDoubleArray. __ sll(scratch, t1, 2); __ Addu(scratch, scratch, FixedDoubleArray::kHeaderSize); - __ Allocate(scratch, t2, t3, t5, &gc_required, DOUBLE_ALIGNMENT); + __ Allocate(scratch, t2, t3, t5, &gc_required, NO_ALLOCATION_FLAGS); // t2: destination FixedDoubleArray, not tagged as heap object // Set destination FixedDoubleArray's length and map. @@ -289,7 +289,7 @@ void ElementsTransitionGenerator::GenerateSmiToDouble( __ SmiTag(t5); __ Or(t5, t5, Operand(1)); __ LoadRoot(at, Heap::kTheHoleValueRootIndex); - __ Assert(eq, kObjectFoundInSmiOnlyArray, at, Operand(t5)); + __ Assert(eq, "object found in smi-only array", at, Operand(t5)); } __ sw(t0, MemOperand(t3)); // mantissa __ sw(t1, MemOperand(t3, kIntSize)); // exponent @@ -489,7 +489,7 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm, // Assert that we do not have a cons or slice (indirect strings) here. // Sequential strings have already been ruled out. __ And(at, result, Operand(kIsIndirectStringMask)); - __ Assert(eq, kExternalStringExpectedButNotFound, + __ Assert(eq, "external string expected, but not found", at, Operand(zero_reg)); } // Rule out short external strings. diff --git a/chromium/v8/src/mips/debug-mips.cc b/chromium/v8/src/mips/debug-mips.cc index 020228fc6b5..30cc4db6340 100644 --- a/chromium/v8/src/mips/debug-mips.cc +++ b/chromium/v8/src/mips/debug-mips.cc @@ -142,7 +142,8 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, if ((non_object_regs & (1 << r)) != 0) { if (FLAG_debug_code) { __ And(at, reg, 0xc0000000); - __ Assert(eq, kUnableToEncodeValueAsSmi, at, Operand(zero_reg)); + __ Assert( + eq, "Unable to encode value as smi", at, Operand(zero_reg)); } __ sll(reg, reg, kSmiTagSize); } @@ -324,12 +325,12 @@ void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) { void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { - masm->Abort(kLiveEditFrameDroppingIsNotSupportedOnMips); + masm->Abort("LiveEdit frame dropping is not supported on mips"); } void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { - masm->Abort(kLiveEditFrameDroppingIsNotSupportedOnMips); + masm->Abort("LiveEdit frame dropping is not supported on mips"); } diff --git a/chromium/v8/src/mips/full-codegen-mips.cc b/chromium/v8/src/mips/full-codegen-mips.cc index b60502c9a5b..1084af09298 100644 --- a/chromium/v8/src/mips/full-codegen-mips.cc +++ b/chromium/v8/src/mips/full-codegen-mips.cc @@ -786,10 +786,10 @@ void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { // Check that we're not inside a with or catch context. __ lw(a1, FieldMemOperand(cp, HeapObject::kMapOffset)); __ LoadRoot(t0, Heap::kWithContextMapRootIndex); - __ Check(ne, kDeclarationInWithContext, + __ Check(ne, "Declaration in with context.", a1, Operand(t0)); __ LoadRoot(t0, Heap::kCatchContextMapRootIndex); - __ Check(ne, kDeclarationInCatchContext, + __ Check(ne, "Declaration in catch context.", a1, Operand(t0)); } } @@ -2529,7 +2529,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, // Check for an uninitialized let binding. __ lw(a2, location); __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); - __ Check(eq, kLetBindingReInitialization, a2, Operand(t0)); + __ Check(eq, "Let binding re-initialization.", a2, Operand(t0)); } // Perform the assignment. __ sw(v0, location); @@ -3492,21 +3492,21 @@ void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string, Register value, uint32_t encoding_mask) { __ And(at, index, Operand(kSmiTagMask)); - __ Check(eq, kNonSmiIndex, at, Operand(zero_reg)); + __ Check(eq, "Non-smi index", at, Operand(zero_reg)); __ And(at, value, Operand(kSmiTagMask)); - __ Check(eq, kNonSmiValue, at, Operand(zero_reg)); + __ Check(eq, "Non-smi value", at, Operand(zero_reg)); __ lw(at, FieldMemOperand(string, String::kLengthOffset)); - __ Check(lt, kIndexIsTooLarge, index, Operand(at)); + __ Check(lt, "Index is too large", index, Operand(at)); - __ Check(ge, kIndexIsNegative, index, Operand(zero_reg)); + __ Check(ge, "Index is negative", index, Operand(zero_reg)); __ lw(at, FieldMemOperand(string, HeapObject::kMapOffset)); __ lbu(at, FieldMemOperand(at, Map::kInstanceTypeOffset)); __ And(at, at, Operand(kStringRepresentationMask | kStringEncodingMask)); __ Subu(at, at, Operand(encoding_mask)); - __ Check(eq, kUnexpectedStringType, at, Operand(zero_reg)); + __ Check(eq, "Unexpected string type", at, Operand(zero_reg)); } @@ -3881,7 +3881,7 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { Handle<FixedArray> jsfunction_result_caches( isolate()->native_context()->jsfunction_result_caches()); if (jsfunction_result_caches->length() <= cache_id) { - __ Abort(kAttemptToUseUndefinedCache); + __ Abort("Attempt to use undefined cache."); __ LoadRoot(v0, Heap::kUndefinedValueRootIndex); context()->Plug(v0); return; @@ -4063,7 +4063,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // element: Current array element. // elements_end: Array end. if (generate_debug_code_) { - __ Assert(gt, kNoEmptyArraysHereInEmitFastAsciiArrayJoin, + __ Assert(gt, "No empty arrays here in EmitFastAsciiArrayJoin", array_length, Operand(zero_reg)); } __ bind(&loop); @@ -4382,12 +4382,35 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { break; } + case Token::SUB: + EmitUnaryOperation(expr, "[ UnaryOperation (SUB)"); + break; + + case Token::BIT_NOT: + EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)"); + break; + default: UNREACHABLE(); } } +void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr, + const char* comment) { + // TODO(svenpanne): Allowing format strings in Comment would be nice here... + Comment cmt(masm_, comment); + UnaryOpStub stub(expr->op()); + // GenericUnaryOpStub expects the argument to be in a0. + VisitForAccumulatorValue(expr->expression()); + SetSourcePosition(expr->position()); + __ mov(a0, result_register()); + CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, + expr->UnaryOperationFeedbackId()); + context()->Plug(v0); +} + + void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { Comment cmnt(masm_, "[ CountOperation"); SetSourcePosition(expr->position()); diff --git a/chromium/v8/src/mips/lithium-codegen-mips.cc b/chromium/v8/src/mips/lithium-codegen-mips.cc index 2bc52e4f3ff..88e7eb8f1d4 100644 --- a/chromium/v8/src/mips/lithium-codegen-mips.cc +++ b/chromium/v8/src/mips/lithium-codegen-mips.cc @@ -91,7 +91,7 @@ void LCodeGen::FinishCode(Handle<Code> code) { } -void LChunkBuilder::Abort(BailoutReason reason) { +void LChunkBuilder::Abort(const char* reason) { info()->set_bailout_reason(reason); status_ = ABORTED; } @@ -268,8 +268,6 @@ bool LCodeGen::GenerateBody() { instr->Mnemonic()); } - RecordAndUpdatePosition(instr->position()); - instr->CompileToNative(this); } EnsureSpaceForLazyDeopt(); @@ -283,10 +281,6 @@ bool LCodeGen::GenerateDeferredCode() { if (deferred_.length() > 0) { for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { LDeferredCode* code = deferred_[i]; - - int pos = instructions_->at(code->instruction_index())->position(); - RecordAndUpdatePosition(pos); - Comment(";;; <@%d,#%d> " "-------------------- Deferred %s --------------------", code->instruction_index(), @@ -330,7 +324,7 @@ bool LCodeGen::GenerateDeoptJumpTable() { // end of the jump table. if (!is_int16((masm()->pc_offset() / Assembler::kInstrSize) + deopt_jump_table_.length() * 12)) { - Abort(kGeneratedCodeIsTooLarge); + Abort("Generated code is too large"); } if (deopt_jump_table_.length() > 0) { @@ -417,7 +411,7 @@ Register LCodeGen::EmitLoadRegister(LOperand* op, Register scratch) { ASSERT(constant->HasSmiValue()); __ li(scratch, Operand(Smi::FromInt(constant->Integer32Value()))); } else if (r.IsDouble()) { - Abort(kEmitLoadRegisterUnsupportedDoubleImmediate); + Abort("EmitLoadRegister: Unsupported double immediate."); } else { ASSERT(r.IsTagged()); __ LoadObject(scratch, literal); @@ -455,9 +449,9 @@ DoubleRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op, __ cvt_d_w(dbl_scratch, flt_scratch); return dbl_scratch; } else if (r.IsDouble()) { - Abort(kUnsupportedDoubleImmediate); + Abort("unsupported double immediate"); } else if (r.IsTagged()) { - Abort(kUnsupportedTaggedImmediate); + Abort("unsupported tagged immediate"); } } else if (op->IsStackSlot() || op->IsArgument()) { MemOperand mem_op = ToMemOperand(op); @@ -526,14 +520,14 @@ Operand LCodeGen::ToOperand(LOperand* op) { ASSERT(constant->HasInteger32Value()); return Operand(constant->Integer32Value()); } else if (r.IsDouble()) { - Abort(kToOperandUnsupportedDoubleImmediate); + Abort("ToOperand Unsupported double immediate."); } ASSERT(r.IsTagged()); return Operand(constant->handle()); } else if (op->IsRegister()) { return Operand(ToRegister(op)); } else if (op->IsDoubleRegister()) { - Abort(kToOperandIsDoubleRegisterUnimplemented); + Abort("ToOperand IsDoubleRegister unimplemented"); return Operand(0); } // Stack slots not implemented, use ToMemOperand instead. @@ -597,57 +591,37 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, break; } - int object_index = 0; - int dematerialized_index = 0; for (int i = 0; i < translation_size; ++i) { LOperand* value = environment->values()->at(i); - AddToTranslation(environment, - translation, + + // TODO(mstarzinger): Introduce marker operands to indicate that this value + // is not present and must be reconstructed from the deoptimizer. Currently + // this is only used for the arguments object. + if (value == NULL) { + int arguments_count = environment->values()->length() - translation_size; + translation->BeginArgumentsObject(arguments_count); + for (int i = 0; i < arguments_count; ++i) { + LOperand* value = environment->values()->at(translation_size + i); + AddToTranslation(translation, + value, + environment->HasTaggedValueAt(translation_size + i), + environment->HasUint32ValueAt(translation_size + i)); + } + continue; + } + + AddToTranslation(translation, value, environment->HasTaggedValueAt(i), - environment->HasUint32ValueAt(i), - &object_index, - &dematerialized_index); + environment->HasUint32ValueAt(i)); } } -void LCodeGen::AddToTranslation(LEnvironment* environment, - Translation* translation, +void LCodeGen::AddToTranslation(Translation* translation, LOperand* op, bool is_tagged, - bool is_uint32, - int* object_index_pointer, - int* dematerialized_index_pointer) { - if (op == LEnvironment::materialization_marker()) { - int object_index = (*object_index_pointer)++; - if (environment->ObjectIsDuplicateAt(object_index)) { - int dupe_of = environment->ObjectDuplicateOfAt(object_index); - translation->DuplicateObject(dupe_of); - return; - } - int object_length = environment->ObjectLengthAt(object_index); - if (environment->ObjectIsArgumentsAt(object_index)) { - translation->BeginArgumentsObject(object_length); - } else { - translation->BeginCapturedObject(object_length); - } - int dematerialized_index = *dematerialized_index_pointer; - int env_offset = environment->translation_size() + dematerialized_index; - *dematerialized_index_pointer += object_length; - for (int i = 0; i < object_length; ++i) { - LOperand* value = environment->values()->at(env_offset + i); - AddToTranslation(environment, - translation, - value, - environment->HasTaggedValueAt(env_offset + i), - environment->HasUint32ValueAt(env_offset + i), - object_index_pointer, - dematerialized_index_pointer); - } - return; - } - + bool is_uint32) { if (op->IsStackSlot()) { if (is_tagged) { translation->StoreStackSlot(op->index()); @@ -774,7 +748,7 @@ void LCodeGen::DeoptimizeIf(Condition cc, Address entry = Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type); if (entry == NULL) { - Abort(kBailoutWasNotPrepared); + Abort("bailout was not prepared"); return; } @@ -787,7 +761,7 @@ void LCodeGen::DeoptimizeIf(Condition cc, return; } - if (info()->ShouldTrapOnDeopt()) { + if (FLAG_trap_on_deopt && info()->IsOptimizing()) { Label skip; if (cc != al) { __ Branch(&skip, NegateCondition(cc), src1, src2); @@ -986,14 +960,6 @@ void LCodeGen::RecordPosition(int position) { } -void LCodeGen::RecordAndUpdatePosition(int position) { - if (position >= 0 && position != old_position_) { - masm()->positions_recorder()->RecordPosition(position); - old_position_ = position; - } -} - - static const char* LabelType(LLabel* label) { if (label->is_loop_header()) return " (loop header)"; if (label->is_osr_entry()) return " (OSR entry)"; @@ -1536,11 +1502,7 @@ void LCodeGen::DoBitI(LBitI* instr) { __ Or(result, left, right); break; case Token::BIT_XOR: - if (right_op->IsConstantOperand() && right.immediate() == int32_t(~0)) { - __ Nor(result, zero_reg, left); - } else { - __ Xor(result, left, right); - } + __ Xor(result, left, right); break; default: UNREACHABLE(); @@ -1801,7 +1763,7 @@ void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; __ Subu(at, at, Operand(encoding == String::ONE_BYTE_ENCODING ? one_byte_seq_type : two_byte_seq_type)); - __ Check(eq, kUnexpectedStringType, at, Operand(zero_reg)); + __ Check(eq, "Unexpected string type", at, Operand(zero_reg)); } __ Addu(scratch, @@ -1818,6 +1780,13 @@ void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { } +void LCodeGen::DoBitNotI(LBitNotI* instr) { + Register input = ToRegister(instr->value()); + Register result = ToRegister(instr->result()); + __ Nor(result, zero_reg, Operand(input)); +} + + void LCodeGen::DoThrow(LThrow* instr) { Register input_reg = EmitLoadRegister(instr->value(), at); __ push(input_reg); @@ -2921,6 +2890,90 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { } +void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, + Register object, + Handle<Map> type, + Handle<String> name, + LEnvironment* env) { + LookupResult lookup(isolate()); + type->LookupDescriptor(NULL, *name, &lookup); + ASSERT(lookup.IsFound() || lookup.IsCacheable()); + if (lookup.IsField()) { + int index = lookup.GetLocalFieldIndexFromMap(*type); + int offset = index * kPointerSize; + if (index < 0) { + // Negative property indices are in-object properties, indexed + // from the end of the fixed part of the object. + __ lw(result, FieldMemOperand(object, offset + type->instance_size())); + } else { + // Non-negative property indices are in the properties array. + __ lw(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); + __ lw(result, FieldMemOperand(result, offset + FixedArray::kHeaderSize)); + } + } else if (lookup.IsConstant()) { + Handle<Object> constant(lookup.GetConstantFromMap(*type), isolate()); + __ LoadObject(result, constant); + } else { + // Negative lookup. + // Check prototypes. + Handle<HeapObject> current(HeapObject::cast((*type)->prototype())); + Heap* heap = type->GetHeap(); + while (*current != heap->null_value()) { + __ LoadHeapObject(result, current); + __ lw(result, FieldMemOperand(result, HeapObject::kMapOffset)); + DeoptimizeIf(ne, env, result, Operand(Handle<Map>(current->map()))); + current = + Handle<HeapObject>(HeapObject::cast(current->map()->prototype())); + } + __ LoadRoot(result, Heap::kUndefinedValueRootIndex); + } +} + + +void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) { + Register object = ToRegister(instr->object()); + Register result = ToRegister(instr->result()); + Register object_map = scratch0(); + + int map_count = instr->hydrogen()->types()->length(); + bool need_generic = instr->hydrogen()->need_generic(); + + if (map_count == 0 && !need_generic) { + DeoptimizeIf(al, instr->environment()); + return; + } + Handle<String> name = instr->hydrogen()->name(); + Label done; + __ lw(object_map, FieldMemOperand(object, HeapObject::kMapOffset)); + for (int i = 0; i < map_count; ++i) { + bool last = (i == map_count - 1); + Handle<Map> map = instr->hydrogen()->types()->at(i); + Label check_passed; + __ CompareMapAndBranch(object_map, map, &check_passed, eq, &check_passed); + if (last && !need_generic) { + DeoptimizeIf(al, instr->environment()); + __ bind(&check_passed); + EmitLoadFieldOrConstantFunction( + result, object, map, name, instr->environment()); + } else { + Label next; + __ Branch(&next); + __ bind(&check_passed); + EmitLoadFieldOrConstantFunction( + result, object, map, name, instr->environment()); + __ Branch(&done); + __ bind(&next); + } + } + if (need_generic) { + __ li(a2, Operand(name)); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); + CallCode(ic, RelocInfo::CODE_TARGET, instr); + } + __ bind(&done); +} + + void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { ASSERT(ToRegister(instr->object()).is(a0)); ASSERT(ToRegister(instr->result()).is(v0)); @@ -3016,7 +3069,7 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { if (key_is_constant) { constant_key = ToInteger32(LConstantOperand::cast(instr->key())); if (constant_key & 0xF0000000) { - Abort(kArrayIndexConstantValueTooBig); + Abort("array index constant value too big."); } } else { key = ToRegister(instr->key()); @@ -3102,7 +3155,7 @@ void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { if (key_is_constant) { constant_key = ToInteger32(LConstantOperand::cast(instr->key())); if (constant_key & 0xF0000000) { - Abort(kArrayIndexConstantValueTooBig); + Abort("array index constant value too big."); } } else { key = ToRegister(instr->key()); @@ -3373,7 +3426,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { void LCodeGen::DoPushArgument(LPushArgument* instr) { LOperand* argument = instr->value(); if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) { - Abort(kDoPushArgumentNotImplementedForDoubleType); + Abort("DoPushArgument not implemented for double type."); } else { Register argument_reg = EmitLoadRegister(argument, at); __ push(argument_reg); @@ -3592,7 +3645,7 @@ void LCodeGen::DoMathAbs(LMathAbs* instr) { FPURegister input = ToDoubleRegister(instr->value()); FPURegister result = ToDoubleRegister(instr->result()); __ abs_d(result, input); - } else if (r.IsSmiOrInteger32()) { + } else if (r.IsInteger32()) { EmitIntegerMathAbs(instr); } else { // Representation is tagged. @@ -4198,7 +4251,7 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { if (key_is_constant) { constant_key = ToInteger32(LConstantOperand::cast(instr->key())); if (constant_key & 0xF0000000) { - Abort(kArrayIndexConstantValueTooBig); + Abort("array index constant value too big."); } } else { key = ToRegister(instr->key()); @@ -4276,7 +4329,7 @@ void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { if (key_is_constant) { constant_key = ToInteger32(LConstantOperand::cast(instr->key())); if (constant_key & 0xF0000000) { - Abort(kArrayIndexConstantValueTooBig); + Abort("array index constant value too big."); } } else { key = ToRegister(instr->key()); @@ -4405,13 +4458,12 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, scratch, GetRAState(), kDontSaveFPRegs); } else { - PushSafepointRegistersScope scope( - this, Safepoint::kWithRegistersAndDoubles); + PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); __ mov(a0, object_reg); __ li(a1, Operand(to_map)); TransitionElementsKindStub stub(from_kind, to_kind); __ CallStub(&stub); - RecordSafepointWithRegistersAndDoubles( + RecordSafepointWithRegisters( instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); } __ bind(¬_applicable); @@ -4717,7 +4769,7 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { __ Move(reg, scratch0(), input_reg); Label canonicalize; __ Branch(&canonicalize, ne, scratch0(), Operand(kHoleNanUpper32)); - __ li(reg, factory()->undefined_value()); + __ li(reg, factory()->the_hole_value()); __ Branch(&done); __ bind(&canonicalize); __ Move(input_reg, @@ -5122,7 +5174,7 @@ void LCodeGen::DoCheckFunction(LCheckFunction* instr) { AllowDeferredHandleDereference smi_check; if (isolate()->heap()->InNewSpace(*target)) { Register reg = ToRegister(instr->value()); - Handle<Cell> cell = isolate()->factory()->NewCell(target); + Handle<Cell> cell = isolate()->factory()->NewPropertyCell(target); __ li(at, Operand(Handle<Object>(cell))); __ lw(at, FieldMemOperand(at, Cell::kValueOffset)); DeoptimizeIf(ne, instr->environment(), reg, @@ -5134,63 +5186,31 @@ void LCodeGen::DoCheckFunction(LCheckFunction* instr) { } -void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) { - { - PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); - __ push(object); - CallRuntimeFromDeferred(Runtime::kMigrateInstance, 1, instr); - __ StoreToSafepointRegisterSlot(v0, scratch0()); - } - __ And(at, scratch0(), Operand(kSmiTagMask)); - DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); +void LCodeGen::DoCheckMapCommon(Register map_reg, + Handle<Map> map, + LEnvironment* env) { + Label success; + __ CompareMapAndBranch(map_reg, map, &success, eq, &success); + DeoptimizeIf(al, env); + __ bind(&success); } void LCodeGen::DoCheckMaps(LCheckMaps* instr) { - class DeferredCheckMaps: public LDeferredCode { - public: - DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object) - : LDeferredCode(codegen), instr_(instr), object_(object) { - SetExit(check_maps()); - } - virtual void Generate() { - codegen()->DoDeferredInstanceMigration(instr_, object_); - } - Label* check_maps() { return &check_maps_; } - virtual LInstruction* instr() { return instr_; } - private: - LCheckMaps* instr_; - Label check_maps_; - Register object_; - }; - if (instr->hydrogen()->CanOmitMapChecks()) return; Register map_reg = scratch0(); LOperand* input = instr->value(); ASSERT(input->IsRegister()); Register reg = ToRegister(input); + Label success; SmallMapList* map_set = instr->hydrogen()->map_set(); __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); - - DeferredCheckMaps* deferred = NULL; - if (instr->hydrogen()->has_migration_target()) { - deferred = new(zone()) DeferredCheckMaps(this, instr, reg); - __ bind(deferred->check_maps()); - } - - Label success; for (int i = 0; i < map_set->length() - 1; i++) { Handle<Map> map = map_set->at(i); __ CompareMapAndBranch(map_reg, map, &success, eq, &success); } Handle<Map> map = map_set->last(); - // Do the CompareMap() directly within the Branch() and DeoptimizeIf(). - if (instr->hydrogen()->has_migration_target()) { - __ Branch(deferred->entry(), ne, map_reg, Operand(map)); - } else { - DeoptimizeIf(ne, instr->environment(), map_reg, Operand(map)); - } - + DoCheckMapCommon(map_reg, map, instr->environment()); __ bind(&success); } @@ -5245,6 +5265,25 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { } +void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { + if (instr->hydrogen()->CanOmitPrototypeChecks()) return; + + Register prototype_reg = ToRegister(instr->temp()); + Register map_reg = ToRegister(instr->temp2()); + + ZoneList<Handle<JSObject> >* prototypes = instr->prototypes(); + ZoneList<Handle<Map> >* maps = instr->maps(); + + ASSERT(prototypes->length() == maps->length()); + + for (int i = 0; i < prototypes->length(); i++) { + __ LoadHeapObject(prototype_reg, prototypes->at(i)); + __ lw(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset)); + DoCheckMapCommon(map_reg, maps->at(i), instr->environment()); + } +} + + void LCodeGen::DoAllocate(LAllocate* instr) { class DeferredAllocate: public LDeferredCode { public: @@ -5625,8 +5664,6 @@ void LCodeGen::DoDeoptimize(LDeoptimize* instr) { if (info()->IsStub() && type == Deoptimizer::EAGER) { type = Deoptimizer::LAZY; } - - Comment(";;; deoptimize: %s", instr->hydrogen()->reason()); DeoptimizeIf(al, instr->environment(), type, zero_reg, Operand(zero_reg)); } diff --git a/chromium/v8/src/mips/lithium-codegen-mips.h b/chromium/v8/src/mips/lithium-codegen-mips.h index b97a3cdbaf1..a485b67db94 100644 --- a/chromium/v8/src/mips/lithium-codegen-mips.h +++ b/chromium/v8/src/mips/lithium-codegen-mips.h @@ -65,8 +65,7 @@ class LCodeGen BASE_EMBEDDED { frame_is_built_(false), safepoints_(info->zone()), resolver_(this), - expected_safepoint_kind_(Safepoint::kSimple), - old_position_(RelocInfo::kNoPosition) { + expected_safepoint_kind_(Safepoint::kSimple) { PopulateDeoptimizationLiteralsWithInlinedFunctions(); } @@ -115,7 +114,7 @@ class LCodeGen BASE_EMBEDDED { DoubleRegister EmitLoadDoubleRegister(LOperand* op, FloatRegister flt_scratch, DoubleRegister dbl_scratch); - int32_t ToRepresentation(LConstantOperand* op, const Representation& r) const; + int ToRepresentation(LConstantOperand* op, const Representation& r) const; int32_t ToInteger32(LConstantOperand* op) const; Smi* ToSmi(LConstantOperand* op) const; double ToDouble(LConstantOperand* op) const; @@ -154,7 +153,7 @@ class LCodeGen BASE_EMBEDDED { void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, Label* map_check); - void DoDeferredInstanceMigration(LCheckMaps* instr, Register object); + void DoCheckMapCommon(Register map_reg, Handle<Map> map, LEnvironment* env); // Parallel move support. void DoParallelMove(LParallelMove* move); @@ -214,7 +213,7 @@ class LCodeGen BASE_EMBEDDED { int GetStackSlotCount() const { return chunk()->spill_slot_count(); } - void Abort(BailoutReason reason); + void Abort(const char* reason); void FPRINTF_CHECKING Comment(const char* format, ...); void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); } @@ -291,13 +290,10 @@ class LCodeGen BASE_EMBEDDED { Register src1 = zero_reg, const Operand& src2 = Operand(zero_reg)); - void AddToTranslation(LEnvironment* environment, - Translation* translation, + void AddToTranslation(Translation* translation, LOperand* op, bool is_tagged, - bool is_uint32, - int* object_index_pointer, - int* dematerialized_index_pointer); + bool is_uint32); void RegisterDependentCodeForEmbeddedMaps(Handle<Code> code); void PopulateDeoptimizationData(Handle<Code> code); int DefineDeoptimizationLiteral(Handle<Object> literal); @@ -323,7 +319,6 @@ class LCodeGen BASE_EMBEDDED { int arguments, Safepoint::DeoptMode mode); void RecordPosition(int position); - void RecordAndUpdatePosition(int position); static Condition TokenToCondition(Token::Value op, bool is_unsigned); void EmitGoto(int block); @@ -378,6 +373,12 @@ class LCodeGen BASE_EMBEDDED { // Caller should branch on equal condition. void EmitIsConstructCall(Register temp1, Register temp2); + void EmitLoadFieldOrConstantFunction(Register result, + Register object, + Handle<Map> type, + Handle<String> name, + LEnvironment* env); + // Emits optimized code to deep-copy the contents of statically known // object graphs (e.g. object literal boilerplate). void EmitDeepCopy(Handle<JSObject> object, @@ -434,8 +435,6 @@ class LCodeGen BASE_EMBEDDED { Safepoint::Kind expected_safepoint_kind_; - int old_position_; - class PushSafepointRegistersScope BASE_EMBEDDED { public: PushSafepointRegistersScope(LCodeGen* codegen, diff --git a/chromium/v8/src/mips/lithium-gap-resolver-mips.cc b/chromium/v8/src/mips/lithium-gap-resolver-mips.cc index 460e13bf0a9..771b22862ee 100644 --- a/chromium/v8/src/mips/lithium-gap-resolver-mips.cc +++ b/chromium/v8/src/mips/lithium-gap-resolver-mips.cc @@ -258,7 +258,7 @@ void LGapResolver::EmitMove(int index) { } else { __ LoadObject(dst, cgen_->ToHandle(constant_source)); } - } else if (destination->IsDoubleRegister()) { + } else if (source->IsDoubleRegister()) { DoubleRegister result = cgen_->ToDoubleRegister(destination); double v = cgen_->ToDouble(constant_source); __ Move(result, v); diff --git a/chromium/v8/src/mips/lithium-mips.cc b/chromium/v8/src/mips/lithium-mips.cc index 23f48a7709d..760be2e6e85 100644 --- a/chromium/v8/src/mips/lithium-mips.cc +++ b/chromium/v8/src/mips/lithium-mips.cc @@ -442,7 +442,7 @@ LPlatformChunk* LChunkBuilder::Build() { } -void LCodeGen::Abort(BailoutReason reason) { +void LCodeGen::Abort(const char* reason) { info()->set_bailout_reason(reason); status_ = ABORTED; } @@ -598,10 +598,8 @@ LInstruction* LChunkBuilder::DefineFixedDouble( LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) { HEnvironment* hydrogen_env = current_block_->last_environment(); int argument_index_accumulator = 0; - ZoneList<HValue*> objects_to_materialize(0, zone()); instr->set_environment(CreateEnvironment(hydrogen_env, - &argument_index_accumulator, - &objects_to_materialize)); + &argument_index_accumulator)); return instr; } @@ -652,7 +650,7 @@ LUnallocated* LChunkBuilder::TempRegister() { new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER); int vreg = allocator_->GetVirtualRegister(); if (!allocator_->AllocationOk()) { - Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister); + Abort("Out of virtual registers while trying to allocate temp register."); vreg = 0; } operand->set_virtual_register(vreg); @@ -890,7 +888,6 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { } #endif - instr->set_position(position_); if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) { instr = AssignPointerMap(instr); } @@ -906,13 +903,11 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { LEnvironment* LChunkBuilder::CreateEnvironment( HEnvironment* hydrogen_env, - int* argument_index_accumulator, - ZoneList<HValue*>* objects_to_materialize) { + int* argument_index_accumulator) { if (hydrogen_env == NULL) return NULL; - LEnvironment* outer = CreateEnvironment(hydrogen_env->outer(), - argument_index_accumulator, - objects_to_materialize); + LEnvironment* outer = + CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator); BailoutId ast_id = hydrogen_env->ast_id(); ASSERT(!ast_id.IsNone() || hydrogen_env->frame_type() != JS_FUNCTION); @@ -927,16 +922,16 @@ LEnvironment* LChunkBuilder::CreateEnvironment( outer, hydrogen_env->entry(), zone()); + bool needs_arguments_object_materialization = false; int argument_index = *argument_index_accumulator; - int object_index = objects_to_materialize->length(); for (int i = 0; i < hydrogen_env->length(); ++i) { if (hydrogen_env->is_special_index(i)) continue; - LOperand* op; HValue* value = hydrogen_env->values()->at(i); - if (value->IsArgumentsObject() || value->IsCapturedObject()) { - objects_to_materialize->Add(value, zone()); - op = LEnvironment::materialization_marker(); + LOperand* op = NULL; + if (value->IsArgumentsObject()) { + needs_arguments_object_materialization = true; + op = NULL; } else if (value->IsPushArgument()) { op = new(zone()) LArgument(argument_index++); } else { @@ -947,33 +942,15 @@ LEnvironment* LChunkBuilder::CreateEnvironment( value->CheckFlag(HInstruction::kUint32)); } - for (int i = object_index; i < objects_to_materialize->length(); ++i) { - HValue* object_to_materialize = objects_to_materialize->at(i); - int previously_materialized_object = -1; - for (int prev = 0; prev < i; ++prev) { - if (objects_to_materialize->at(prev) == objects_to_materialize->at(i)) { - previously_materialized_object = prev; - break; - } - } - int length = object_to_materialize->OperandCount(); - bool is_arguments = object_to_materialize->IsArgumentsObject(); - if (previously_materialized_object >= 0) { - result->AddDuplicateObject(previously_materialized_object); - continue; - } else { - result->AddNewObject(is_arguments ? length - 1 : length, is_arguments); - } - for (int i = is_arguments ? 1 : 0; i < length; ++i) { - LOperand* op; - HValue* value = object_to_materialize->OperandAt(i); - if (value->IsArgumentsObject() || value->IsCapturedObject()) { - objects_to_materialize->Add(value, zone()); - op = LEnvironment::materialization_marker(); - } else { - ASSERT(!value->IsPushArgument()); - op = UseAny(value); - } + if (needs_arguments_object_materialization) { + HArgumentsObject* arguments = hydrogen_env->entry() == NULL + ? graph()->GetArgumentsObject() + : hydrogen_env->entry()->arguments_object(); + ASSERT(arguments->IsLinked()); + for (int i = 1; i < arguments->arguments_count(); ++i) { + HValue* value = arguments->arguments_values()->at(i); + ASSERT(!value->IsArgumentsObject() && !value->IsPushArgument()); + LOperand* op = UseAny(value); result->AddValue(op, value->representation(), value->CheckFlag(HInstruction::kUint32)); @@ -1350,6 +1327,15 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { } +LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) { + ASSERT(instr->value()->representation().IsInteger32()); + ASSERT(instr->representation().IsInteger32()); + if (instr->HasNoUses()) return NULL; + LOperand* value = UseRegisterAtStart(instr->value()); + return DefineAsRegister(new(zone()) LBitNotI(value)); +} + + LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { if (instr->representation().IsDouble()) { return DoArithmeticD(Token::DIV, instr); @@ -1628,8 +1614,9 @@ LInstruction* LChunkBuilder::DoCompareNumericAndBranch( HCompareNumericAndBranch* instr) { Representation r = instr->representation(); if (r.IsSmiOrInteger32()) { - ASSERT(instr->left()->representation().Equals(r)); - ASSERT(instr->right()->representation().Equals(r)); + ASSERT(instr->left()->representation().IsSmiOrInteger32()); + ASSERT(instr->left()->representation().Equals( + instr->right()->representation())); LOperand* left = UseRegisterOrConstantAtStart(instr->left()); LOperand* right = UseRegisterOrConstantAtStart(instr->right()); return new(zone()) LCompareNumericAndBranch(left, right); @@ -1764,6 +1751,17 @@ LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) { } +LInstruction* LChunkBuilder::DoNumericConstraint(HNumericConstraint* instr) { + return NULL; +} + + +LInstruction* LChunkBuilder::DoInductionVariableAnnotation( + HInductionVariableAnnotation* instr) { + return NULL; +} + + LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { LOperand* value = UseRegisterOrConstantAtStart(instr->index()); LOperand* length = UseRegister(instr->length()); @@ -1937,6 +1935,19 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { } +LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) { + LUnallocated* temp1 = NULL; + LOperand* temp2 = NULL; + if (!instr->CanOmitPrototypeChecks()) { + temp1 = TempRegister(); + temp2 = TempRegister(); + } + LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp1, temp2); + if (instr->CanOmitPrototypeChecks()) return result; + return AssignEnvironment(result); +} + + LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { LOperand* value = UseRegisterAtStart(instr->value()); return AssignEnvironment(new(zone()) LCheckFunction(value)); @@ -1945,16 +1956,10 @@ LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) { LOperand* value = NULL; - if (!instr->CanOmitMapChecks()) { - value = UseRegisterAtStart(instr->value()); - if (instr->has_migration_target()) info()->MarkAsDeferredCalling(); - } - LCheckMaps* result = new(zone()) LCheckMaps(value); - if (!instr->CanOmitMapChecks()) { - AssignEnvironment(result); - if (instr->has_migration_target()) return AssignPointerMap(result); - } - return result; + if (!instr->CanOmitMapChecks()) value = UseRegisterAtStart(instr->value()); + LInstruction* result = new(zone()) LCheckMaps(value); + if (instr->CanOmitMapChecks()) return result; + return AssignEnvironment(result); } @@ -2066,6 +2071,23 @@ LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) { } +LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic( + HLoadNamedFieldPolymorphic* instr) { + ASSERT(instr->representation().IsTagged()); + if (instr->need_generic()) { + LOperand* obj = UseFixed(instr->object(), a0); + LLoadNamedFieldPolymorphic* result = + new(zone()) LLoadNamedFieldPolymorphic(obj); + return MarkAsCall(DefineFixed(result, v0), instr); + } else { + LOperand* obj = UseRegisterAtStart(instr->object()); + LLoadNamedFieldPolymorphic* result = + new(zone()) LLoadNamedFieldPolymorphic(obj); + return AssignEnvironment(DefineAsRegister(result)); + } +} + + LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { LOperand* object = UseFixed(instr->object(), a0); LInstruction* result = DefineFixed(new(zone()) LLoadNamedGeneric(object), v0); @@ -2221,7 +2243,7 @@ LInstruction* LChunkBuilder::DoTrapAllocationMemento( LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) { bool is_in_object = instr->access().IsInobject(); bool needs_write_barrier = instr->NeedsWriteBarrier(); - bool needs_write_barrier_for_map = instr->has_transition() && + bool needs_write_barrier_for_map = !instr->transition().is_null() && instr->NeedsWriteBarrierForMap(); LOperand* obj; @@ -2341,7 +2363,7 @@ LInstruction* LChunkBuilder::DoParameter(HParameter* instr) { LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) { int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width. if (spill_index > LUnallocated::kMaxFixedSlotIndex) { - Abort(kTooManySpillSlotsNeededForOSR); + Abort("Too many spill slots needed for OSR"); spill_index = 0; } return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index); @@ -2363,12 +2385,6 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) { } -LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) { - // There are no real uses of a captured object. - return NULL; -} - - LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) { info()->MarkAsRequiresFrame(); LOperand* args = UseRegister(instr->arguments()); diff --git a/chromium/v8/src/mips/lithium-mips.h b/chromium/v8/src/mips/lithium-mips.h index a1792b17b22..44c909ea766 100644 --- a/chromium/v8/src/mips/lithium-mips.h +++ b/chromium/v8/src/mips/lithium-mips.h @@ -50,6 +50,7 @@ class LCodeGen; V(ArithmeticD) \ V(ArithmeticT) \ V(BitI) \ + V(BitNotI) \ V(BoundsCheck) \ V(Branch) \ V(CallConstantFunction) \ @@ -67,6 +68,7 @@ class LCodeGen; V(CheckMaps) \ V(CheckMapValue) \ V(CheckNonSmi) \ + V(CheckPrototypeMaps) \ V(CheckSmi) \ V(ClampDToUint8) \ V(ClampIToUint8) \ @@ -126,6 +128,7 @@ class LCodeGen; V(LoadKeyed) \ V(LoadKeyedGeneric) \ V(LoadNamedField) \ + V(LoadNamedFieldPolymorphic) \ V(LoadNamedGeneric) \ V(MapEnumLength) \ V(MathAbs) \ @@ -204,12 +207,9 @@ class LCodeGen; class LInstruction: public ZoneObject { public: LInstruction() - : environment_(NULL), - hydrogen_value_(NULL), - bit_field_(IsCallBits::encode(false)) { - set_position(RelocInfo::kNoPosition); - } - + : environment_(NULL), + hydrogen_value_(NULL), + is_call_(false) { } virtual ~LInstruction() { } virtual void CompileToNative(LCodeGen* generator) = 0; @@ -248,30 +248,20 @@ class LInstruction: public ZoneObject { LPointerMap* pointer_map() const { return pointer_map_.get(); } bool HasPointerMap() const { return pointer_map_.is_set(); } - // The 31 bits PositionBits is used to store the int position value. And the - // position value may be RelocInfo::kNoPosition (-1). The accessor always - // +1/-1 so that the encoded value of position in bit_field_ is always >= 0 - // and can fit into the 31 bits PositionBits. - void set_position(int pos) { - bit_field_ = PositionBits::update(bit_field_, pos + 1); - } - int position() { return PositionBits::decode(bit_field_) - 1; } - void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; } HValue* hydrogen_value() const { return hydrogen_value_; } virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { } - void MarkAsCall() { bit_field_ = IsCallBits::update(bit_field_, true); } - bool IsCall() const { return IsCallBits::decode(bit_field_); } + void MarkAsCall() { is_call_ = true; } // Interface to the register allocator and iterators. - bool ClobbersTemps() const { return IsCall(); } - bool ClobbersRegisters() const { return IsCall(); } - bool ClobbersDoubleRegisters() const { return IsCall(); } + bool ClobbersTemps() const { return is_call_; } + bool ClobbersRegisters() const { return is_call_; } + bool ClobbersDoubleRegisters() const { return is_call_; } // Interface to the register allocator and iterators. - bool IsMarkedAsCall() const { return IsCall(); } + bool IsMarkedAsCall() const { return is_call_; } virtual bool HasResult() const = 0; virtual LOperand* result() const = 0; @@ -295,13 +285,10 @@ class LInstruction: public ZoneObject { virtual int TempCount() = 0; virtual LOperand* TempAt(int i) = 0; - class IsCallBits: public BitField<bool, 0, 1> {}; - class PositionBits: public BitField<int, 1, 31> {}; - LEnvironment* environment_; SetOncePointer<LPointerMap> pointer_map_; HValue* hydrogen_value_; - int bit_field_; + bool is_call_; }; @@ -1369,6 +1356,18 @@ class LThrow: public LTemplateInstruction<0, 1, 0> { }; +class LBitNotI: public LTemplateInstruction<1, 1, 0> { + public: + explicit LBitNotI(LOperand* value) { + inputs_[0] = value; + } + + LOperand* value() { return inputs_[0]; } + + DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i") +}; + + class LAddI: public LTemplateInstruction<1, 2, 0> { public: LAddI(LOperand* left, LOperand* right) { @@ -1504,6 +1503,19 @@ class LLoadNamedField: public LTemplateInstruction<1, 1, 0> { }; +class LLoadNamedFieldPolymorphic: public LTemplateInstruction<1, 1, 0> { + public: + explicit LLoadNamedFieldPolymorphic(LOperand* object) { + inputs_[0] = object; + } + + LOperand* object() { return inputs_[0]; } + + DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field-polymorphic") + DECLARE_HYDROGEN_ACCESSOR(LoadNamedFieldPolymorphic) +}; + + class LLoadNamedGeneric: public LTemplateInstruction<1, 1, 0> { public: explicit LLoadNamedGeneric(LOperand* object) { @@ -2116,7 +2128,7 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 1> { virtual void PrintDataTo(StringStream* stream); - Handle<Map> transition() const { return hydrogen()->transition_map(); } + Handle<Map> transition() const { return hydrogen()->transition(); } Representation representation() const { return hydrogen()->field_representation(); } @@ -2312,6 +2324,26 @@ class LCheckMaps: public LTemplateInstruction<0, 1, 0> { }; +class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 2> { + public: + LCheckPrototypeMaps(LOperand* temp, LOperand* temp2) { + temps_[0] = temp; + temps_[1] = temp2; + } + + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps") + DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps) + + ZoneList<Handle<JSObject> >* prototypes() const { + return hydrogen()->prototypes(); + } + ZoneList<Handle<Map> >* maps() const { return hydrogen()->maps(); } +}; + + class LCheckSmi: public LTemplateInstruction<1, 1, 0> { public: explicit LCheckSmi(LOperand* value) { @@ -2610,7 +2642,7 @@ class LChunkBuilder BASE_EMBEDDED { bool is_done() const { return status_ == DONE; } bool is_aborted() const { return status_ == ABORTED; } - void Abort(BailoutReason reason); + void Abort(const char* reason); // Methods for getting operands for Use / Define / Temp. LUnallocated* ToUnallocated(Register reg); @@ -2692,8 +2724,7 @@ class LChunkBuilder BASE_EMBEDDED { CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY); LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, - int* argument_index_accumulator, - ZoneList<HValue*>* objects_to_materialize); + int* argument_index_accumulator); void VisitInstruction(HInstruction* current); diff --git a/chromium/v8/src/mips/macro-assembler-mips.cc b/chromium/v8/src/mips/macro-assembler-mips.cc index e53f10afaca..ea08a552be5 100644 --- a/chromium/v8/src/mips/macro-assembler-mips.cc +++ b/chromium/v8/src/mips/macro-assembler-mips.cc @@ -256,7 +256,7 @@ void MacroAssembler::RecordWrite(Register object, if (emit_debug_code()) { lw(at, MemOperand(address)); Assert( - eq, kWrongAddressOrValuePassedToRecordWrite, at, Operand(value)); + eq, "Wrong address or value passed to RecordWrite", at, Operand(value)); } Label done; @@ -358,7 +358,7 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, lw(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset)); // In debug mode, make sure the lexical context is set. #ifdef DEBUG - Check(ne, kWeShouldNotHaveAnEmptyLexicalContext, + Check(ne, "we should not have an empty lexical context", scratch, Operand(zero_reg)); #endif @@ -374,7 +374,7 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, // Read the first word and compare to the native_context_map. lw(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset)); LoadRoot(at, Heap::kNativeContextMapRootIndex); - Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext, + Check(eq, "JSGlobalObject::native_context should be a native context.", holder_reg, Operand(at)); pop(holder_reg); // Restore holder. } @@ -388,12 +388,12 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, push(holder_reg); // Temporarily save holder on the stack. mov(holder_reg, at); // Move at to its holding place. LoadRoot(at, Heap::kNullValueRootIndex); - Check(ne, kJSGlobalProxyContextShouldNotBeNull, + Check(ne, "JSGlobalProxy::context() should not be null.", holder_reg, Operand(at)); lw(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset)); LoadRoot(at, Heap::kNativeContextMapRootIndex); - Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext, + Check(eq, "JSGlobalObject::native_context should be a native context.", holder_reg, Operand(at)); // Restore at is not needed. at is reloaded below. pop(holder_reg); // Restore holder. @@ -2923,7 +2923,9 @@ void MacroAssembler::Allocate(int object_size, // Set up allocation top address and object size registers. Register topaddr = scratch1; + Register obj_size_reg = scratch2; li(topaddr, Operand(allocation_top)); + li(obj_size_reg, Operand(object_size)); // This code stores a temporary value in t9. if ((flags & RESULT_CONTAINS_TOP) == 0) { @@ -2936,29 +2938,15 @@ void MacroAssembler::Allocate(int object_size, // immediately below so this use of t9 does not cause difference with // respect to register content between debug and release mode. lw(t9, MemOperand(topaddr)); - Check(eq, kUnexpectedAllocationTop, result, Operand(t9)); + Check(eq, "Unexpected allocation top", result, Operand(t9)); } // Load allocation limit into t9. Result already contains allocation top. lw(t9, MemOperand(topaddr, limit - top)); } - if ((flags & DOUBLE_ALIGNMENT) != 0) { - // Align the next allocation. Storing the filler map without checking top is - // always safe because the limit of the heap is always aligned. - ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0); - ASSERT(kPointerAlignment * 2 == kDoubleAlignment); - And(scratch2, result, Operand(kDoubleAlignmentMask)); - Label aligned; - Branch(&aligned, eq, scratch2, Operand(zero_reg)); - li(scratch2, Operand(isolate()->factory()->one_pointer_filler_map())); - sw(scratch2, MemOperand(result)); - Addu(result, result, Operand(kDoubleSize / 2)); - bind(&aligned); - } - // Calculate new top and bail out if new space is exhausted. Use result // to calculate the new top. - Addu(scratch2, result, Operand(object_size)); + Addu(scratch2, result, Operand(obj_size_reg)); Branch(gc_required, Ugreater, scratch2, Operand(t9)); sw(scratch2, MemOperand(topaddr)); @@ -3020,26 +3008,12 @@ void MacroAssembler::Allocate(Register object_size, // immediately below so this use of t9 does not cause difference with // respect to register content between debug and release mode. lw(t9, MemOperand(topaddr)); - Check(eq, kUnexpectedAllocationTop, result, Operand(t9)); + Check(eq, "Unexpected allocation top", result, Operand(t9)); } // Load allocation limit into t9. Result already contains allocation top. lw(t9, MemOperand(topaddr, limit - top)); } - if ((flags & DOUBLE_ALIGNMENT) != 0) { - // Align the next allocation. Storing the filler map without checking top is - // always safe because the limit of the heap is always aligned. - ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0); - ASSERT(kPointerAlignment * 2 == kDoubleAlignment); - And(scratch2, result, Operand(kDoubleAlignmentMask)); - Label aligned; - Branch(&aligned, eq, scratch2, Operand(zero_reg)); - li(scratch2, Operand(isolate()->factory()->one_pointer_filler_map())); - sw(scratch2, MemOperand(result)); - Addu(result, result, Operand(kDoubleSize / 2)); - bind(&aligned); - } - // Calculate new top and bail out if new space is exhausted. Use result // to calculate the new top. Object size may be in words so a shift is // required to get the number of bytes. @@ -3054,7 +3028,7 @@ void MacroAssembler::Allocate(Register object_size, // Update allocation top. result temporarily holds the new top. if (emit_debug_code()) { And(t9, scratch2, Operand(kObjectAlignmentMask)); - Check(eq, kUnalignedAllocationInNewSpace, t9, Operand(zero_reg)); + Check(eq, "Unaligned allocation in new space", t9, Operand(zero_reg)); } sw(scratch2, MemOperand(topaddr)); @@ -3076,7 +3050,7 @@ void MacroAssembler::UndoAllocationInNewSpace(Register object, // Check that the object un-allocated is below the current top. li(scratch, Operand(new_space_allocation_top)); lw(scratch, MemOperand(scratch)); - Check(less, kUndoAllocationOfNonAllocatedMemory, + Check(less, "Undo allocation of non allocated memory", object, Operand(scratch)); #endif // Write the address of the object to un-allocate as the current top. @@ -3329,7 +3303,7 @@ void MacroAssembler::CopyBytes(Register src, bind(&word_loop); if (emit_debug_code()) { And(scratch, src, kPointerSize - 1); - Assert(eq, kExpectingAlignmentForCopyBytes, + Assert(eq, "Expecting alignment for CopyBytes", scratch, Operand(zero_reg)); } Branch(&byte_loop, lt, length, Operand(kPointerSize)); @@ -4055,7 +4029,7 @@ void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function, sw(s0, MemOperand(s3, kNextOffset)); if (emit_debug_code()) { lw(a1, MemOperand(s3, kLevelOffset)); - Check(eq, kUnexpectedLevelAfterReturnFromApiCall, a1, Operand(s2)); + Check(eq, "Unexpected level after return from api call", a1, Operand(s2)); } Subu(s2, s2, Operand(1)); sw(s2, MemOperand(s3, kLevelOffset)); @@ -4409,10 +4383,10 @@ void MacroAssembler::DecrementCounter(StatsCounter* counter, int value, // ----------------------------------------------------------------------------- // Debugging. -void MacroAssembler::Assert(Condition cc, BailoutReason reason, +void MacroAssembler::Assert(Condition cc, const char* msg, Register rs, Operand rt) { if (emit_debug_code()) - Check(cc, reason, rs, rt); + Check(cc, msg, rs, rt); } @@ -4420,7 +4394,7 @@ void MacroAssembler::AssertRegisterIsRoot(Register reg, Heap::RootListIndex index) { if (emit_debug_code()) { LoadRoot(at, index); - Check(eq, kRegisterDidNotMatchExpectedRoot, reg, Operand(at)); + Check(eq, "Register did not match expected root", reg, Operand(at)); } } @@ -4437,24 +4411,24 @@ void MacroAssembler::AssertFastElements(Register elements) { Branch(&ok, eq, elements, Operand(at)); LoadRoot(at, Heap::kFixedCOWArrayMapRootIndex); Branch(&ok, eq, elements, Operand(at)); - Abort(kJSObjectWithFastElementsMapHasSlowElements); + Abort("JSObject with fast elements map has slow elements"); bind(&ok); pop(elements); } } -void MacroAssembler::Check(Condition cc, BailoutReason reason, +void MacroAssembler::Check(Condition cc, const char* msg, Register rs, Operand rt) { Label L; Branch(&L, cc, rs, rt); - Abort(reason); + Abort(msg); // Will not return here. bind(&L); } -void MacroAssembler::Abort(BailoutReason reason) { +void MacroAssembler::Abort(const char* msg) { Label abort_start; bind(&abort_start); // We want to pass the msg string like a smi to avoid GC @@ -4462,7 +4436,6 @@ void MacroAssembler::Abort(BailoutReason reason) { // properly. Instead, we pass an aligned pointer that is // a proper v8 smi, but also pass the alignment difference // from the real pointer as a smi. - const char* msg = GetBailoutReason(reason); intptr_t p1 = reinterpret_cast<intptr_t>(msg); intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag; ASSERT(reinterpret_cast<Object*>(p0)->IsSmi()); @@ -4606,7 +4579,7 @@ void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK); Branch(&ok); bind(&fail); - Abort(kGlobalFunctionsMustHaveInitialMap); + Abort("Global functions must have initial map"); bind(&ok); } } @@ -4889,7 +4862,7 @@ void MacroAssembler::AssertNotSmi(Register object) { if (emit_debug_code()) { STATIC_ASSERT(kSmiTag == 0); andi(at, object, kSmiTagMask); - Check(ne, kOperandIsASmi, at, Operand(zero_reg)); + Check(ne, "Operand is a smi", at, Operand(zero_reg)); } } @@ -4898,7 +4871,7 @@ void MacroAssembler::AssertSmi(Register object) { if (emit_debug_code()) { STATIC_ASSERT(kSmiTag == 0); andi(at, object, kSmiTagMask); - Check(eq, kOperandIsASmi, at, Operand(zero_reg)); + Check(eq, "Operand is a smi", at, Operand(zero_reg)); } } @@ -4907,11 +4880,11 @@ void MacroAssembler::AssertString(Register object) { if (emit_debug_code()) { STATIC_ASSERT(kSmiTag == 0); And(t0, object, Operand(kSmiTagMask)); - Check(ne, kOperandIsASmiAndNotAString, t0, Operand(zero_reg)); + Check(ne, "Operand is a smi and not a string", t0, Operand(zero_reg)); push(object); lw(object, FieldMemOperand(object, HeapObject::kMapOffset)); lbu(object, FieldMemOperand(object, Map::kInstanceTypeOffset)); - Check(lo, kOperandIsNotAString, object, Operand(FIRST_NONSTRING_TYPE)); + Check(lo, "Operand is not a string", object, Operand(FIRST_NONSTRING_TYPE)); pop(object); } } @@ -4921,11 +4894,11 @@ void MacroAssembler::AssertName(Register object) { if (emit_debug_code()) { STATIC_ASSERT(kSmiTag == 0); And(t0, object, Operand(kSmiTagMask)); - Check(ne, kOperandIsASmiAndNotAName, t0, Operand(zero_reg)); + Check(ne, "Operand is a smi and not a name", t0, Operand(zero_reg)); push(object); lw(object, FieldMemOperand(object, HeapObject::kMapOffset)); lbu(object, FieldMemOperand(object, Map::kInstanceTypeOffset)); - Check(le, kOperandIsNotAName, object, Operand(LAST_NAME_TYPE)); + Check(le, "Operand is not a name", object, Operand(LAST_NAME_TYPE)); pop(object); } } @@ -4933,11 +4906,11 @@ void MacroAssembler::AssertName(Register object) { void MacroAssembler::AssertRootValue(Register src, Heap::RootListIndex root_value_index, - BailoutReason reason) { + const char* message) { if (emit_debug_code()) { ASSERT(!src.is(at)); LoadRoot(at, root_value_index); - Check(eq, reason, src, Operand(at)); + Check(eq, message, src, Operand(at)); } } @@ -5154,7 +5127,7 @@ void MacroAssembler::PatchRelocatedValue(Register li_location, // At this point scratch is a lui(at, ...) instruction. if (emit_debug_code()) { And(scratch, scratch, kOpcodeMask); - Check(eq, kTheInstructionToPatchShouldBeALui, + Check(eq, "The instruction to patch should be a lui.", scratch, Operand(LUI)); lw(scratch, MemOperand(li_location)); } @@ -5166,7 +5139,7 @@ void MacroAssembler::PatchRelocatedValue(Register li_location, // scratch is now ori(at, ...). if (emit_debug_code()) { And(scratch, scratch, kOpcodeMask); - Check(eq, kTheInstructionToPatchShouldBeAnOri, + Check(eq, "The instruction to patch should be an ori.", scratch, Operand(ORI)); lw(scratch, MemOperand(li_location, kInstrSize)); } @@ -5183,7 +5156,7 @@ void MacroAssembler::GetRelocatedValue(Register li_location, lw(value, MemOperand(li_location)); if (emit_debug_code()) { And(value, value, kOpcodeMask); - Check(eq, kTheInstructionShouldBeALui, + Check(eq, "The instruction should be a lui.", value, Operand(LUI)); lw(value, MemOperand(li_location)); } @@ -5194,7 +5167,7 @@ void MacroAssembler::GetRelocatedValue(Register li_location, lw(scratch, MemOperand(li_location, kInstrSize)); if (emit_debug_code()) { And(scratch, scratch, kOpcodeMask); - Check(eq, kTheInstructionShouldBeAnOri, + Check(eq, "The instruction should be an ori.", scratch, Operand(ORI)); lw(scratch, MemOperand(li_location, kInstrSize)); } diff --git a/chromium/v8/src/mips/macro-assembler-mips.h b/chromium/v8/src/mips/macro-assembler-mips.h index 61a0c3a228f..bc3e7c48b4a 100644 --- a/chromium/v8/src/mips/macro-assembler-mips.h +++ b/chromium/v8/src/mips/macro-assembler-mips.h @@ -51,6 +51,20 @@ class JumpTarget; // MIPS generated code calls C code, it must be via t9 register. +// Flags used for the AllocateInNewSpace functions. +enum AllocationFlags { + // No special flags. + NO_ALLOCATION_FLAGS = 0, + // Return the pointer to the allocated already tagged as a heap object. + TAG_OBJECT = 1 << 0, + // The content of the result register already contains the allocation top in + // new space. + RESULT_CONTAINS_TOP = 1 << 1, + // Specify that the requested size of the space to allocate is specified in + // words instead of bytes. + SIZE_IN_WORDS = 1 << 2 +}; + // Flags used for AllocateHeapNumber enum TaggingMode { // Tag the result. @@ -613,11 +627,11 @@ class MacroAssembler: public Assembler { void MultiPushFPU(RegList regs); void MultiPushReversedFPU(RegList regs); + // Lower case push() for compatibility with arch-independent code. void push(Register src) { Addu(sp, sp, Operand(-kPointerSize)); sw(src, MemOperand(sp, 0)); } - void Push(Register src) { push(src); } // Push a handle. void Push(Handle<Object> handle); @@ -662,11 +676,11 @@ class MacroAssembler: public Assembler { void MultiPopFPU(RegList regs); void MultiPopReversedFPU(RegList regs); + // Lower case pop() for compatibility with arch-independent code. void pop(Register dst) { lw(dst, MemOperand(sp, 0)); Addu(sp, sp, Operand(kPointerSize)); } - void Pop(Register dst) { pop(dst); } // Pop two registers. Pops rightmost register first (from lower address). void Pop(Register src1, Register src2) { @@ -1272,15 +1286,15 @@ class MacroAssembler: public Assembler { // Calls Abort(msg) if the condition cc is not satisfied. // Use --debug_code to enable. - void Assert(Condition cc, BailoutReason reason, Register rs, Operand rt); + void Assert(Condition cc, const char* msg, Register rs, Operand rt); void AssertRegisterIsRoot(Register reg, Heap::RootListIndex index); void AssertFastElements(Register elements); // Like Assert(), but always enabled. - void Check(Condition cc, BailoutReason reason, Register rs, Operand rt); + void Check(Condition cc, const char* msg, Register rs, Operand rt); // Print a message to stdout and abort execution. - void Abort(BailoutReason msg); + void Abort(const char* msg); // Verify restrictions about code generated in stubs. void set_generating_stub(bool value) { generating_stub_ = value; } @@ -1364,7 +1378,7 @@ class MacroAssembler: public Assembler { // enabled via --debug-code. void AssertRootValue(Register src, Heap::RootListIndex root_value_index, - BailoutReason reason); + const char* message); // --------------------------------------------------------------------------- // HeapNumber utilities. diff --git a/chromium/v8/src/object-observe.js b/chromium/v8/src/object-observe.js index f5e0d9d563a..a5c12bf0098 100644 --- a/chromium/v8/src/object-observe.js +++ b/chromium/v8/src/object-observe.js @@ -394,10 +394,7 @@ function ObjectGetNotifier(object) { if (ObjectIsFrozen(object)) return null; var objectInfo = objectInfoMap.get(object); - if (IS_UNDEFINED(objectInfo)) { - objectInfo = CreateObjectInfo(object); - %SetIsObserved(object); - } + if (IS_UNDEFINED(objectInfo)) objectInfo = CreateObjectInfo(object); if (IS_NULL(objectInfo.notifier)) { objectInfo.notifier = { __proto__: notifierPrototype }; diff --git a/chromium/v8/src/objects-debug.cc b/chromium/v8/src/objects-debug.cc index e0cb8c92948..395f95ca7ea 100644 --- a/chromium/v8/src/objects-debug.cc +++ b/chromium/v8/src/objects-debug.cc @@ -366,12 +366,9 @@ void Map::SharedMapVerify() { } -void Map::VerifyOmittedMapChecks() { - if (!FLAG_omit_map_checks_for_leaf_maps) return; - if (!is_stable() || - is_deprecated() || - HasTransitionArray() || - is_dictionary_map()) { +void Map::VerifyOmittedPrototypeChecks() { + if (!FLAG_omit_prototype_checks_for_leaf_maps) return; + if (HasTransitionArray() || is_dictionary_map()) { CHECK_EQ(0, dependent_code()->number_of_entries( DependentCode::kPrototypeCheckGroup)); } diff --git a/chromium/v8/src/objects-inl.h b/chromium/v8/src/objects-inl.h index 169475791d0..128dc6be281 100644 --- a/chromium/v8/src/objects-inl.h +++ b/chromium/v8/src/objects-inl.h @@ -3617,17 +3617,6 @@ bool Map::is_deprecated() { } -void Map::set_migration_target(bool value) { - set_bit_field3(IsMigrationTarget::update(bit_field3(), value)); -} - - -bool Map::is_migration_target() { - if (!FLAG_track_fields) return false; - return IsMigrationTarget::decode(bit_field3()); -} - - void Map::freeze() { set_bit_field3(IsFrozen::update(bit_field3(), true)); } @@ -3688,6 +3677,11 @@ void Map::NotifyLeafMapLayoutChange() { } +bool Map::CanOmitPrototypeChecks() { + return is_stable() && FLAG_omit_prototype_checks_for_leaf_maps; +} + + bool Map::CanOmitMapChecks() { return is_stable() && FLAG_omit_map_checks_for_leaf_maps; } @@ -3822,6 +3816,7 @@ inline void Code::set_is_crankshafted(bool value) { int Code::major_key() { ASSERT(kind() == STUB || + kind() == UNARY_OP_IC || kind() == BINARY_OP_IC || kind() == COMPARE_IC || kind() == COMPARE_NIL_IC || @@ -3836,6 +3831,7 @@ int Code::major_key() { void Code::set_major_key(int major) { ASSERT(kind() == STUB || + kind() == UNARY_OP_IC || kind() == BINARY_OP_IC || kind() == COMPARE_IC || kind() == COMPARE_NIL_IC || @@ -4025,6 +4021,21 @@ void Code::set_check_type(CheckType value) { } +byte Code::unary_op_type() { + ASSERT(is_unary_op_stub()); + return UnaryOpTypeField::decode( + READ_UINT32_FIELD(this, kKindSpecificFlags1Offset)); +} + + +void Code::set_unary_op_type(byte value) { + ASSERT(is_unary_op_stub()); + int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset); + int updated = UnaryOpTypeField::update(previous, value); + WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated); +} + + byte Code::to_boolean_state() { return extended_extra_ic_state(); } @@ -4209,20 +4220,7 @@ void Map::InitializeDescriptors(DescriptorArray* descriptors) { ACCESSORS(Map, instance_descriptors, DescriptorArray, kDescriptorsOffset) - - -void Map::set_bit_field3(uint32_t bits) { - // Ensure the upper 2 bits have the same value by sign extending it. This is - // necessary to be able to use the 31st bit. - int value = bits << 1; - WRITE_FIELD(this, kBitField3Offset, Smi::FromInt(value >> 1)); -} - - -uint32_t Map::bit_field3() { - Object* value = READ_FIELD(this, kBitField3Offset); - return Smi::cast(value)->value(); -} +SMI_ACCESSORS(Map, bit_field3, kBitField3Offset) void Map::ClearTransitions(Heap* heap, WriteBarrierMode mode) { diff --git a/chromium/v8/src/objects-printer.cc b/chromium/v8/src/objects-printer.cc index 7b6f7a478ce..87b2811e413 100644 --- a/chromium/v8/src/objects-printer.cc +++ b/chromium/v8/src/objects-printer.cc @@ -37,6 +37,9 @@ namespace internal { #ifdef OBJECT_PRINT +static const char* TypeToString(InstanceType type); + + void MaybeObject::Print() { Print(stdout); } @@ -506,12 +509,83 @@ void JSModule::JSModulePrint(FILE* out) { static const char* TypeToString(InstanceType type) { switch (type) { -#define TYPE_TO_STRING(TYPE) case TYPE: return #TYPE; - INSTANCE_TYPE_LIST(TYPE_TO_STRING) -#undef TYPE_TO_STRING + case INVALID_TYPE: return "INVALID"; + case MAP_TYPE: return "MAP"; + case HEAP_NUMBER_TYPE: return "HEAP_NUMBER"; + case SYMBOL_TYPE: return "SYMBOL"; + case STRING_TYPE: return "TWO_BYTE_STRING"; + case ASCII_STRING_TYPE: return "ASCII_STRING"; + case CONS_STRING_TYPE: + case CONS_ASCII_STRING_TYPE: + return "CONS_STRING"; + case EXTERNAL_STRING_TYPE: + case EXTERNAL_ASCII_STRING_TYPE: + case EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE: + return "EXTERNAL_STRING"; + case SHORT_EXTERNAL_STRING_TYPE: + case SHORT_EXTERNAL_ASCII_STRING_TYPE: + case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE: + return "SHORT_EXTERNAL_STRING"; + case INTERNALIZED_STRING_TYPE: return "INTERNALIZED_STRING"; + case ASCII_INTERNALIZED_STRING_TYPE: return "ASCII_INTERNALIZED_STRING"; + case CONS_INTERNALIZED_STRING_TYPE: return "CONS_INTERNALIZED_STRING"; + case CONS_ASCII_INTERNALIZED_STRING_TYPE: + return "CONS_ASCII_INTERNALIZED_STRING"; + case EXTERNAL_INTERNALIZED_STRING_TYPE: + case EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE: + case EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE: + return "EXTERNAL_INTERNALIZED_STRING"; + case SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE: + case SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE: + case SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE: + return "SHORT_EXTERNAL_INTERNALIZED_STRING"; + case FIXED_ARRAY_TYPE: return "FIXED_ARRAY"; + case BYTE_ARRAY_TYPE: return "BYTE_ARRAY"; + case FREE_SPACE_TYPE: return "FREE_SPACE"; + case EXTERNAL_PIXEL_ARRAY_TYPE: return "EXTERNAL_PIXEL_ARRAY"; + case EXTERNAL_BYTE_ARRAY_TYPE: return "EXTERNAL_BYTE_ARRAY"; + case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: + return "EXTERNAL_UNSIGNED_BYTE_ARRAY"; + case EXTERNAL_SHORT_ARRAY_TYPE: return "EXTERNAL_SHORT_ARRAY"; + case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: + return "EXTERNAL_UNSIGNED_SHORT_ARRAY"; + case EXTERNAL_INT_ARRAY_TYPE: return "EXTERNAL_INT_ARRAY"; + case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: + return "EXTERNAL_UNSIGNED_INT_ARRAY"; + case EXTERNAL_FLOAT_ARRAY_TYPE: return "EXTERNAL_FLOAT_ARRAY"; + case EXTERNAL_DOUBLE_ARRAY_TYPE: return "EXTERNAL_DOUBLE_ARRAY"; + case FILLER_TYPE: return "FILLER"; + case JS_OBJECT_TYPE: return "JS_OBJECT"; + case JS_CONTEXT_EXTENSION_OBJECT_TYPE: return "JS_CONTEXT_EXTENSION_OBJECT"; + case ODDBALL_TYPE: return "ODDBALL"; + case CELL_TYPE: return "CELL"; + case PROPERTY_CELL_TYPE: return "PROPERTY_CELL"; + case SHARED_FUNCTION_INFO_TYPE: return "SHARED_FUNCTION_INFO"; + case JS_GENERATOR_OBJECT_TYPE: return "JS_GENERATOR_OBJECT"; + case JS_MODULE_TYPE: return "JS_MODULE"; + case JS_FUNCTION_TYPE: return "JS_FUNCTION"; + case CODE_TYPE: return "CODE"; + case JS_ARRAY_TYPE: return "JS_ARRAY"; + case JS_PROXY_TYPE: return "JS_PROXY"; + case JS_SET_TYPE: return "JS_SET"; + case JS_MAP_TYPE: return "JS_MAP"; + case JS_WEAK_MAP_TYPE: return "JS_WEAK_MAP"; + case JS_WEAK_SET_TYPE: return "JS_WEAK_SET"; + case JS_REGEXP_TYPE: return "JS_REGEXP"; + case JS_VALUE_TYPE: return "JS_VALUE"; + case JS_GLOBAL_OBJECT_TYPE: return "JS_GLOBAL_OBJECT"; + case JS_BUILTINS_OBJECT_TYPE: return "JS_BUILTINS_OBJECT"; + case JS_GLOBAL_PROXY_TYPE: return "JS_GLOBAL_PROXY"; + case JS_ARRAY_BUFFER_TYPE: return "JS_ARRAY_BUFFER"; + case JS_TYPED_ARRAY_TYPE: return "JS_TYPED_ARRAY"; + case JS_DATA_VIEW_TYPE: return "JS_DATA_VIEW"; + case FOREIGN_TYPE: return "FOREIGN"; + case JS_MESSAGE_OBJECT_TYPE: return "JS_MESSAGE_OBJECT_TYPE"; +#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: return #NAME; + STRUCT_LIST(MAKE_STRUCT_CASE) +#undef MAKE_STRUCT_CASE + default: return "UNKNOWN"; } - UNREACHABLE(); - return "UNKNOWN"; // Keep the compiler happy. } diff --git a/chromium/v8/src/objects-visiting.h b/chromium/v8/src/objects-visiting.h index 21757377a4f..32e457b869a 100644 --- a/chromium/v8/src/objects-visiting.h +++ b/chromium/v8/src/objects-visiting.h @@ -141,7 +141,7 @@ class StaticVisitorBase : public AllStatic { (base == kVisitJSObject)); ASSERT(IsAligned(object_size, kPointerSize)); ASSERT(kMinObjectSizeInWords * kPointerSize <= object_size); - ASSERT(object_size <= Page::kMaxNonCodeHeapObjectSize); + ASSERT(object_size < Page::kMaxNonCodeHeapObjectSize); const VisitorId specialization = static_cast<VisitorId>( base + (object_size >> kPointerSizeLog2) - kMinObjectSizeInWords); diff --git a/chromium/v8/src/objects.cc b/chromium/v8/src/objects.cc index 995ed36f022..2e9badbb2aa 100644 --- a/chromium/v8/src/objects.cc +++ b/chromium/v8/src/objects.cc @@ -2719,7 +2719,6 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index, Handle<Map>(new_map); return maybe_map; } - new_map->set_migration_target(true); } new_map->set_owns_descriptors(true); @@ -6518,7 +6517,6 @@ MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, result->set_is_shared(sharing == SHARED_NORMALIZED_MAP); result->set_dictionary_map(true); - result->set_migration_target(false); #ifdef VERIFY_HEAP if (FLAG_verify_heap && result->is_shared()) { @@ -9222,7 +9220,6 @@ void JSFunction::MarkForLazyRecompilation() { ASSERT(!IsOptimized()); ASSERT(shared()->allows_lazy_compilation() || code()->optimizable()); - ASSERT(!shared()->is_generator()); set_code_no_write_barrier( GetIsolate()->builtins()->builtin(Builtins::kLazyRecompile)); // No write barrier required, since the builtin is part of the root set. @@ -9233,8 +9230,10 @@ void JSFunction::MarkForParallelRecompilation() { ASSERT(is_compiled() || GetIsolate()->DebuggerHasBreakPoints()); ASSERT(!IsOptimized()); ASSERT(shared()->allows_lazy_compilation() || code()->optimizable()); - ASSERT(!shared()->is_generator()); - ASSERT(FLAG_parallel_recompilation); + if (!FLAG_parallel_recompilation) { + JSFunction::MarkForLazyRecompilation(); + return; + } if (FLAG_trace_parallel_recompilation) { PrintF(" ** Marking "); PrintName(); @@ -9805,7 +9804,7 @@ void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) { } -void SharedFunctionInfo::DisableOptimization(BailoutReason reason) { +void SharedFunctionInfo::DisableOptimization(const char* reason) { // Disable optimization for the shared function info and mark the // code as non-optimizable. The marker on the shared function info // is there because we flush non-optimized code thereby loosing the @@ -9823,7 +9822,7 @@ void SharedFunctionInfo::DisableOptimization(BailoutReason reason) { if (FLAG_trace_opt) { PrintF("[disabled optimization for "); ShortPrint(); - PrintF(", reason: %s]\n", GetBailoutReason(reason)); + PrintF(", reason: %s]\n", reason); } } @@ -10636,14 +10635,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) { break; } - case Translation::DUPLICATED_OBJECT: { - int object_index = iterator.Next(); - PrintF(out, "{object_index=%d}", object_index); - break; - } - - case Translation::ARGUMENTS_OBJECT: - case Translation::CAPTURED_OBJECT: { + case Translation::ARGUMENTS_OBJECT: { int args_length = iterator.Next(); PrintF(out, "{length=%d}", args_length); break; @@ -10801,17 +10793,18 @@ void Code::Disassemble(const char* name, FILE* out) { // If there is no back edge table, the "table start" will be at or after // (due to alignment) the end of the instruction stream. if (static_cast<int>(offset) < instruction_size()) { - FullCodeGenerator::BackEdgeTableIterator back_edges(this); - - PrintF(out, "Back edges (size = %u)\n", back_edges.table_length()); + Address back_edge_cursor = instruction_start() + offset; + uint32_t table_length = Memory::uint32_at(back_edge_cursor); + PrintF(out, "Back edges (size = %u)\n", table_length); PrintF(out, "ast_id pc_offset loop_depth\n"); - - for ( ; !back_edges.Done(); back_edges.Next()) { - PrintF(out, "%6d %9u %10u\n", back_edges.ast_id().ToInt(), - back_edges.pc_offset(), - back_edges.loop_depth()); + for (uint32_t i = 0; i < table_length; ++i) { + uint32_t ast_id = Memory::uint32_at(back_edge_cursor); + uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize); + uint32_t loop_depth = Memory::uint32_at(back_edge_cursor + + 2 * kIntSize); + PrintF(out, "%6u %9u %10u\n", ast_id, pc_offset, loop_depth); + back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize; } - PrintF(out, "\n"); } #ifdef OBJECT_PRINT @@ -11354,7 +11347,6 @@ bool DependentCode::Contains(DependencyGroup group, Code* code) { void DependentCode::DeoptimizeDependentCodeGroup( Isolate* isolate, DependentCode::DependencyGroup group) { - ASSERT(AllowCodeDependencyChange::IsAllowed()); DisallowHeapAllocation no_allocation_scope; DependentCode::GroupStartIndexes starts(this); int start = starts.at(group); @@ -15972,15 +15964,4 @@ void PropertyCell::AddDependentCode(Handle<Code> code) { } -const char* GetBailoutReason(BailoutReason reason) { - ASSERT(reason < kLastErrorMessage); -#define ERROR_MESSAGES_TEXTS(C, T) T, - static const char* error_messages_[] = { - ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) - }; -#undef ERROR_MESSAGES_TEXTS - return error_messages_[reason]; -} - - } } // namespace v8::internal diff --git a/chromium/v8/src/objects.h b/chromium/v8/src/objects.h index f800c5d580e..d370c32a1a4 100644 --- a/chromium/v8/src/objects.h +++ b/chromium/v8/src/objects.h @@ -333,7 +333,6 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; V(CONS_STRING_TYPE) \ V(CONS_ASCII_STRING_TYPE) \ V(SLICED_STRING_TYPE) \ - V(SLICED_ASCII_STRING_TYPE) \ V(EXTERNAL_STRING_TYPE) \ V(EXTERNAL_ASCII_STRING_TYPE) \ V(EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE) \ @@ -417,8 +416,6 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; V(JS_TYPED_ARRAY_TYPE) \ V(JS_DATA_VIEW_TYPE) \ V(JS_PROXY_TYPE) \ - V(JS_SET_TYPE) \ - V(JS_MAP_TYPE) \ V(JS_WEAK_MAP_TYPE) \ V(JS_WEAK_SET_TYPE) \ V(JS_REGEXP_TYPE) \ @@ -786,6 +783,7 @@ enum InstanceType { // Pseudo-types FIRST_TYPE = 0x0, LAST_TYPE = JS_FUNCTION_TYPE, + INVALID_TYPE = FIRST_TYPE - 1, FIRST_NAME_TYPE = FIRST_TYPE, LAST_NAME_TYPE = SYMBOL_TYPE, FIRST_UNIQUE_NAME_TYPE = INTERNALIZED_STRING_TYPE, @@ -1048,287 +1046,7 @@ class MaybeObject BASE_EMBEDDED { V(AccessCheckNeeded) \ V(Cell) \ V(PropertyCell) \ - V(ObjectHashTable) - - -#define ERROR_MESSAGES_LIST(V) \ - V(kNoReason, "no reason") \ - \ - V(k32BitValueInRegisterIsNotZeroExtended, \ - "32 bit value in register is not zero-extended") \ - V(kAlignmentMarkerExpected, "alignment marker expected") \ - V(kAllocationIsNotDoubleAligned, "Allocation is not double aligned") \ - V(kAPICallReturnedInvalidObject, "API call returned invalid object") \ - V(kArgumentsObjectValueInATestContext, \ - "arguments object value in a test context") \ - V(kArrayBoilerplateCreationFailed, "array boilerplate creation failed") \ - V(kArrayIndexConstantValueTooBig, "array index constant value too big") \ - V(kAssignmentToArguments, "assignment to arguments") \ - V(kAssignmentToLetVariableBeforeInitialization, \ - "assignment to let variable before initialization") \ - V(kAssignmentToLOOKUPVariable, "assignment to LOOKUP variable") \ - V(kAssignmentToParameterFunctionUsesArgumentsObject, \ - "assignment to parameter, function uses arguments object") \ - V(kAssignmentToParameterInArgumentsObject, \ - "assignment to parameter in arguments object") \ - V(kAttemptToUseUndefinedCache, "Attempt to use undefined cache") \ - V(kBadValueContextForArgumentsObjectValue, \ - "bad value context for arguments object value") \ - V(kBadValueContextForArgumentsValue, \ - "bad value context for arguments value") \ - V(kBailedOutDueToDependencyChange, "bailed out due to dependency change") \ - V(kBailoutWasNotPrepared, "bailout was not prepared") \ - V(kBinaryStubGenerateFloatingPointCode, \ - "BinaryStub_GenerateFloatingPointCode") \ - V(kBothRegistersWereSmisInSelectNonSmi, \ - "Both registers were smis in SelectNonSmi") \ - V(kCallToAJavaScriptRuntimeFunction, \ - "call to a JavaScript runtime function") \ - V(kCannotTranslatePositionInChangedArea, \ - "Cannot translate position in changed area") \ - V(kCodeGenerationFailed, "code generation failed") \ - V(kCodeObjectNotProperlyPatched, "code object not properly patched") \ - V(kCompoundAssignmentToLookupSlot, "compound assignment to lookup slot") \ - V(kContextAllocatedArguments, "context-allocated arguments") \ - V(kDebuggerIsActive, "debugger is active") \ - V(kDebuggerStatement, "DebuggerStatement") \ - V(kDeclarationInCatchContext, "Declaration in catch context") \ - V(kDeclarationInWithContext, "Declaration in with context") \ - V(kDefaultNaNModeNotSet, "Default NaN mode not set") \ - V(kDeleteWithGlobalVariable, "delete with global variable") \ - V(kDeleteWithNonGlobalVariable, "delete with non-global variable") \ - V(kDestinationOfCopyNotAligned, "Destination of copy not aligned") \ - V(kDontDeleteCellsCannotContainTheHole, \ - "DontDelete cells can't contain the hole") \ - V(kDoPushArgumentNotImplementedForDoubleType, \ - "DoPushArgument not implemented for double type") \ - V(kEmitLoadRegisterUnsupportedDoubleImmediate, \ - "EmitLoadRegister: Unsupported double immediate") \ - V(kEval, "eval") \ - V(kExpected0AsASmiSentinel, "Expected 0 as a Smi sentinel") \ - V(kExpectedAlignmentMarker, "expected alignment marker") \ - V(kExpectedPropertyCellInRegisterA2, \ - "Expected property cell in register a2") \ - V(kExpectedPropertyCellInRegisterEbx, \ - "Expected property cell in register ebx") \ - V(kExpectedPropertyCellInRegisterRbx, \ - "Expected property cell in register rbx") \ - V(kExpectingAlignmentForCopyBytes, \ - "Expecting alignment for CopyBytes") \ - V(kExternalStringExpectedButNotFound, \ - "external string expected, but not found") \ - V(kFailedBailedOutLastTime, "failed/bailed out last time") \ - V(kForInStatementIsNotFastCase, "ForInStatement is not fast case") \ - V(kForInStatementOptimizationIsDisabled, \ - "ForInStatement optimization is disabled") \ - V(kForInStatementWithNonLocalEachVariable, \ - "ForInStatement with non-local each variable") \ - V(kForOfStatement, "ForOfStatement") \ - V(kFrameIsExpectedToBeAligned, "frame is expected to be aligned") \ - V(kFunctionCallsEval, "function calls eval") \ - V(kFunctionIsAGenerator, "function is a generator") \ - V(kFunctionWithIllegalRedeclaration, "function with illegal redeclaration") \ - V(kGeneratedCodeIsTooLarge, "Generated code is too large") \ - V(kGeneratorFailedToResume, "Generator failed to resume") \ - V(kGenerator, "generator") \ - V(kGlobalFunctionsMustHaveInitialMap, \ - "Global functions must have initial map") \ - V(kHeapNumberMapRegisterClobbered, "HeapNumberMap register clobbered") \ - V(kImproperObjectOnPrototypeChainForStore, \ - "improper object on prototype chain for store") \ - V(kIndexIsNegative, "Index is negative") \ - V(kIndexIsTooLarge, "Index is too large") \ - V(kInlinedRuntimeFunctionClassOf, "inlined runtime function: ClassOf") \ - V(kInlinedRuntimeFunctionFastAsciiArrayJoin, \ - "inlined runtime function: FastAsciiArrayJoin") \ - V(kInlinedRuntimeFunctionGeneratorNext, \ - "inlined runtime function: GeneratorNext") \ - V(kInlinedRuntimeFunctionGeneratorThrow, \ - "inlined runtime function: GeneratorThrow") \ - V(kInlinedRuntimeFunctionGetFromCache, \ - "inlined runtime function: GetFromCache") \ - V(kInlinedRuntimeFunctionIsNonNegativeSmi, \ - "inlined runtime function: IsNonNegativeSmi") \ - V(kInlinedRuntimeFunctionIsRegExpEquivalent, \ - "inlined runtime function: IsRegExpEquivalent") \ - V(kInlinedRuntimeFunctionIsStringWrapperSafeForDefaultValueOf, \ - "inlined runtime function: IsStringWrapperSafeForDefaultValueOf") \ - V(kInliningBailedOut, "inlining bailed out") \ - V(kInputGPRIsExpectedToHaveUpper32Cleared, \ - "input GPR is expected to have upper32 cleared") \ - V(kInstanceofStubUnexpectedCallSiteCacheCheck, \ - "InstanceofStub unexpected call site cache (check)") \ - V(kInstanceofStubUnexpectedCallSiteCacheCmp1, \ - "InstanceofStub unexpected call site cache (cmp 1)") \ - V(kInstanceofStubUnexpectedCallSiteCacheCmp2, \ - "InstanceofStub unexpected call site cache (cmp 2)") \ - V(kInstanceofStubUnexpectedCallSiteCacheMov, \ - "InstanceofStub unexpected call site cache (mov)") \ - V(kInteger32ToSmiFieldWritingToNonSmiLocation, \ - "Integer32ToSmiField writing to non-smi location") \ - V(kInvalidCaptureReferenced, "Invalid capture referenced") \ - V(kInvalidElementsKindForInternalArrayOrInternalPackedArray, \ - "Invalid ElementsKind for InternalArray or InternalPackedArray") \ - V(kInvalidHandleScopeLevel, "Invalid HandleScope level") \ - V(kInvalidLeftHandSideInAssignment, "invalid left-hand side in assignment") \ - V(kInvalidLhsInCompoundAssignment, "invalid lhs in compound assignment") \ - V(kInvalidLhsInCountOperation, "invalid lhs in count operation") \ - V(kInvalidMinLength, "Invalid min_length") \ - V(kJSGlobalObjectNativeContextShouldBeANativeContext, \ - "JSGlobalObject::native_context should be a native context") \ - V(kJSGlobalProxyContextShouldNotBeNull, \ - "JSGlobalProxy::context() should not be null") \ - V(kJSObjectWithFastElementsMapHasSlowElements, \ - "JSObject with fast elements map has slow elements") \ - V(kLetBindingReInitialization, "Let binding re-initialization") \ - V(kLiveBytesCountOverflowChunkSize, "Live Bytes Count overflow chunk size") \ - V(kLiveEditFrameDroppingIsNotSupportedOnArm, \ - "LiveEdit frame dropping is not supported on arm") \ - V(kLiveEditFrameDroppingIsNotSupportedOnMips, \ - "LiveEdit frame dropping is not supported on mips") \ - V(kLiveEdit, "LiveEdit") \ - V(kLookupVariableInCountOperation, \ - "lookup variable in count operation") \ - V(kMapIsNoLongerInEax, "Map is no longer in eax") \ - V(kNoCasesLeft, "no cases left") \ - V(kNoEmptyArraysHereInEmitFastAsciiArrayJoin, \ - "No empty arrays here in EmitFastAsciiArrayJoin") \ - V(kNonInitializerAssignmentToConst, \ - "non-initializer assignment to const") \ - V(kNonSmiIndex, "Non-smi index") \ - V(kNonSmiKeyInArrayLiteral, "Non-smi key in array literal") \ - V(kNonSmiValue, "Non-smi value") \ - V(kNotEnoughVirtualRegistersForValues, \ - "not enough virtual registers for values") \ - V(kNotEnoughVirtualRegistersRegalloc, \ - "not enough virtual registers (regalloc)") \ - V(kObjectFoundInSmiOnlyArray, "object found in smi-only array") \ - V(kObjectLiteralWithComplexProperty, \ - "Object literal with complex property") \ - V(kOddballInStringTableIsNotUndefinedOrTheHole, \ - "oddball in string table is not undefined or the hole") \ - V(kOperandIsASmiAndNotAName, "Operand is a smi and not a name") \ - V(kOperandIsASmiAndNotAString, "Operand is a smi and not a string") \ - V(kOperandIsASmi, "Operand is a smi") \ - V(kOperandIsNotAName, "Operand is not a name") \ - V(kOperandIsNotANumber, "Operand is not a number") \ - V(kOperandIsNotASmi, "Operand is not a smi") \ - V(kOperandIsNotAString, "Operand is not a string") \ - V(kOperandIsNotSmi, "Operand is not smi") \ - V(kOperandNotANumber, "Operand not a number") \ - V(kOptimizedTooManyTimes, "optimized too many times") \ - V(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister, \ - "Out of virtual registers while trying to allocate temp register") \ - V(kParseScopeError, "parse/scope error") \ - V(kPossibleDirectCallToEval, "possible direct call to eval") \ - V(kPropertyAllocationCountFailed, "Property allocation count failed") \ - V(kReceivedInvalidReturnAddress, "Received invalid return address") \ - V(kReferenceToAVariableWhichRequiresDynamicLookup, \ - "reference to a variable which requires dynamic lookup") \ - V(kReferenceToGlobalLexicalVariable, \ - "reference to global lexical variable") \ - V(kReferenceToUninitializedVariable, "reference to uninitialized variable") \ - V(kRegisterDidNotMatchExpectedRoot, "Register did not match expected root") \ - V(kRegisterWasClobbered, "register was clobbered") \ - V(kScopedBlock, "ScopedBlock") \ - V(kSharedFunctionInfoLiteral, "SharedFunctionInfoLiteral") \ - V(kSmiAdditionOverflow, "Smi addition overflow") \ - V(kSmiSubtractionOverflow, "Smi subtraction overflow") \ - V(kStackFrameTypesMustMatch, "stack frame types must match") \ - V(kSwitchStatementMixedOrNonLiteralSwitchLabels, \ - "SwitchStatement: mixed or non-literal switch labels") \ - V(kSwitchStatementTooManyClauses, "SwitchStatement: too many clauses") \ - V(kTheInstructionShouldBeALui, "The instruction should be a lui") \ - V(kTheInstructionShouldBeAnOri, "The instruction should be an ori") \ - V(kTheInstructionToPatchShouldBeALoadFromPc, \ - "The instruction to patch should be a load from pc") \ - V(kTheInstructionToPatchShouldBeALui, \ - "The instruction to patch should be a lui") \ - V(kTheInstructionToPatchShouldBeAnOri, \ - "The instruction to patch should be an ori") \ - V(kTooManyParametersLocals, "too many parameters/locals") \ - V(kTooManyParameters, "too many parameters") \ - V(kTooManySpillSlotsNeededForOSR, "Too many spill slots needed for OSR") \ - V(kToOperandIsDoubleRegisterUnimplemented, \ - "ToOperand IsDoubleRegister unimplemented") \ - V(kToOperandUnsupportedDoubleImmediate, \ - "ToOperand Unsupported double immediate") \ - V(kTryCatchStatement, "TryCatchStatement") \ - V(kTryFinallyStatement, "TryFinallyStatement") \ - V(kUnableToEncodeValueAsSmi, "Unable to encode value as smi") \ - V(kUnalignedAllocationInNewSpace, "Unaligned allocation in new space") \ - V(kUndefinedValueNotLoaded, "Undefined value not loaded") \ - V(kUndoAllocationOfNonAllocatedMemory, \ - "Undo allocation of non allocated memory") \ - V(kUnexpectedAllocationTop, "Unexpected allocation top") \ - V(kUnexpectedElementsKindInArrayConstructor, \ - "Unexpected ElementsKind in array constructor") \ - V(kUnexpectedFallthroughFromCharCodeAtSlowCase, \ - "Unexpected fallthrough from CharCodeAt slow case") \ - V(kUnexpectedFallthroughFromCharFromCodeSlowCase, \ - "Unexpected fallthrough from CharFromCode slow case") \ - V(kUnexpectedFallThroughFromStringComparison, \ - "Unexpected fall-through from string comparison") \ - V(kUnexpectedFallThroughInBinaryStubGenerateFloatingPointCode, \ - "Unexpected fall-through in BinaryStub_GenerateFloatingPointCode") \ - V(kUnexpectedFallthroughToCharCodeAtSlowCase, \ - "Unexpected fallthrough to CharCodeAt slow case") \ - V(kUnexpectedFallthroughToCharFromCodeSlowCase, \ - "Unexpected fallthrough to CharFromCode slow case") \ - V(kUnexpectedFPUStackDepthAfterInstruction, \ - "Unexpected FPU stack depth after instruction") \ - V(kUnexpectedInitialMapForArrayFunction1, \ - "Unexpected initial map for Array function (1)") \ - V(kUnexpectedInitialMapForArrayFunction2, \ - "Unexpected initial map for Array function (2)") \ - V(kUnexpectedInitialMapForArrayFunction, \ - "Unexpected initial map for Array function") \ - V(kUnexpectedInitialMapForInternalArrayFunction, \ - "Unexpected initial map for InternalArray function") \ - V(kUnexpectedLevelAfterReturnFromApiCall, \ - "Unexpected level after return from api call") \ - V(kUnexpectedNumberOfPreAllocatedPropertyFields, \ - "Unexpected number of pre-allocated property fields") \ - V(kUnexpectedStringFunction, "Unexpected String function") \ - V(kUnexpectedStringType, "Unexpected string type") \ - V(kUnexpectedStringWrapperInstanceSize, \ - "Unexpected string wrapper instance size") \ - V(kUnexpectedTypeForRegExpDataFixedArrayExpected, \ - "Unexpected type for RegExp data, FixedArray expected") \ - V(kUnexpectedUnusedPropertiesOfStringWrapper, \ - "Unexpected unused properties of string wrapper") \ - V(kUninitializedKSmiConstantRegister, "Uninitialized kSmiConstantRegister") \ - V(kUnknown, "unknown") \ - V(kUnsupportedConstCompoundAssignment, \ - "unsupported const compound assignment") \ - V(kUnsupportedCountOperationWithConst, \ - "unsupported count operation with const") \ - V(kUnsupportedDoubleImmediate, "unsupported double immediate") \ - V(kUnsupportedLetCompoundAssignment, "unsupported let compound assignment") \ - V(kUnsupportedLookupSlotInDeclaration, \ - "unsupported lookup slot in declaration") \ - V(kUnsupportedNonPrimitiveCompare, "Unsupported non-primitive compare") \ - V(kUnsupportedPhiUseOfArguments, "Unsupported phi use of arguments") \ - V(kUnsupportedPhiUseOfConstVariable, \ - "Unsupported phi use of const variable") \ - V(kUnsupportedTaggedImmediate, "unsupported tagged immediate") \ - V(kVariableResolvedToWithContext, "Variable resolved to with context") \ - V(kWeShouldNotHaveAnEmptyLexicalContext, \ - "we should not have an empty lexical context") \ - V(kWithStatement, "WithStatement") \ - V(kWrongAddressOrValuePassedToRecordWrite, \ - "Wrong address or value passed to RecordWrite") - - -#define ERROR_MESSAGES_CONSTANTS(C, T) C, -enum BailoutReason { - ERROR_MESSAGES_LIST(ERROR_MESSAGES_CONSTANTS) - kLastErrorMessage -}; -#undef ERROR_MESSAGES_CONSTANTS - - -const char* GetBailoutReason(BailoutReason reason); + V(ObjectHashTable) \ // Object is the abstract superclass for all classes in the @@ -4783,6 +4501,7 @@ class Code: public HeapObject { V(KEYED_CALL_IC) \ V(STORE_IC) \ V(KEYED_STORE_IC) \ + V(UNARY_OP_IC) \ V(BINARY_OP_IC) \ V(COMPARE_IC) \ V(COMPARE_NIL_IC) \ @@ -4901,7 +4620,8 @@ class Code: public HeapObject { // TODO(danno): This is a bit of a hack right now since there are still // clients of this API that pass "extra" values in for argc. These clients // should be retrofitted to used ExtendedExtraICState. - return kind == COMPARE_NIL_IC || kind == TO_BOOLEAN_IC; + return kind == COMPARE_NIL_IC || kind == TO_BOOLEAN_IC || + kind == UNARY_OP_IC; } inline StubType type(); // Only valid for monomorphic IC stubs. @@ -4916,6 +4636,7 @@ class Code: public HeapObject { inline bool is_keyed_store_stub() { return kind() == KEYED_STORE_IC; } inline bool is_call_stub() { return kind() == CALL_IC; } inline bool is_keyed_call_stub() { return kind() == KEYED_CALL_IC; } + inline bool is_unary_op_stub() { return kind() == UNARY_OP_IC; } inline bool is_binary_op_stub() { return kind() == BINARY_OP_IC; } inline bool is_compare_ic_stub() { return kind() == COMPARE_IC; } inline bool is_compare_nil_ic_stub() { return kind() == COMPARE_NIL_IC; } @@ -4989,6 +4710,10 @@ class Code: public HeapObject { inline CheckType check_type(); inline void set_check_type(CheckType value); + // [type-recording unary op type]: For kind UNARY_OP_IC. + inline byte unary_op_type(); + inline void set_unary_op_type(byte value); + // [to_boolean_foo]: For kind TO_BOOLEAN_IC tells what state the stub is in. inline byte to_boolean_state(); @@ -5227,6 +4952,9 @@ class Code: public HeapObject { // KindSpecificFlags1 layout (STUB and OPTIMIZED_FUNCTION) static const int kStackSlotsFirstBit = 0; static const int kStackSlotsBitCount = 24; + static const int kUnaryOpTypeFirstBit = + kStackSlotsFirstBit + kStackSlotsBitCount; + static const int kUnaryOpTypeBitCount = 3; static const int kHasFunctionCacheFirstBit = kStackSlotsFirstBit + kStackSlotsBitCount; static const int kHasFunctionCacheBitCount = 1; @@ -5235,12 +4963,15 @@ class Code: public HeapObject { static const int kMarkedForDeoptimizationBitCount = 1; STATIC_ASSERT(kStackSlotsFirstBit + kStackSlotsBitCount <= 32); + STATIC_ASSERT(kUnaryOpTypeFirstBit + kUnaryOpTypeBitCount <= 32); STATIC_ASSERT(kHasFunctionCacheFirstBit + kHasFunctionCacheBitCount <= 32); STATIC_ASSERT(kMarkedForDeoptimizationFirstBit + kMarkedForDeoptimizationBitCount <= 32); class StackSlotsField: public BitField<int, kStackSlotsFirstBit, kStackSlotsBitCount> {}; // NOLINT + class UnaryOpTypeField: public BitField<int, + kUnaryOpTypeFirstBit, kUnaryOpTypeBitCount> {}; // NOLINT class HasFunctionCacheField: public BitField<bool, kHasFunctionCacheFirstBit, kHasFunctionCacheBitCount> {}; // NOLINT class MarkedForDeoptimizationField: public BitField<bool, @@ -5445,8 +5176,8 @@ class Map: public HeapObject { inline void set_bit_field2(byte value); // Bit field 3. - inline uint32_t bit_field3(); - inline void set_bit_field3(uint32_t bits); + inline int bit_field3(); + inline void set_bit_field3(int value); class EnumLengthBits: public BitField<int, 0, 11> {}; class NumberOfOwnDescriptorsBits: public BitField<int, 11, 11> {}; @@ -5458,7 +5189,6 @@ class Map: public HeapObject { class Deprecated: public BitField<bool, 27, 1> {}; class IsFrozen: public BitField<bool, 28, 1> {}; class IsUnstable: public BitField<bool, 29, 1> {}; - class IsMigrationTarget: public BitField<bool, 30, 1> {}; // Tells whether the object in the prototype property will be used // for instances created from this function. If the prototype @@ -5765,8 +5495,6 @@ class Map: public HeapObject { inline bool is_frozen(); inline void mark_unstable(); inline bool is_stable(); - inline void set_migration_target(bool value); - inline bool is_migration_target(); inline void deprecate(); inline bool is_deprecated(); inline bool CanBeDeprecated(); @@ -5913,6 +5641,7 @@ class Map: public HeapObject { // the descriptor array. inline void NotifyLeafMapLayoutChange(); + inline bool CanOmitPrototypeChecks(); inline bool CanOmitMapChecks(); void AddDependentCompilationInfo(DependentCode::DependencyGroup group, @@ -5929,7 +5658,7 @@ class Map: public HeapObject { #ifdef VERIFY_HEAP void SharedMapVerify(); - void VerifyOmittedMapChecks(); + void VerifyOmittedPrototypeChecks(); #endif inline int visitor_id(); @@ -6576,7 +6305,7 @@ class SharedFunctionInfo: public HeapObject { // Disable (further) attempted optimization of all functions sharing this // shared function info. - void DisableOptimization(BailoutReason reason); + void DisableOptimization(const char* reason); // Lookup the bailout ID and ASSERT that it exists in the non-optimized // code, returns whether it asserted (i.e., always true if assertions are @@ -10058,7 +9787,6 @@ class BreakPointInfo: public Struct { V(kHandleScope, "handlescope", "(Handle scope)") \ V(kBuiltins, "builtins", "(Builtins)") \ V(kGlobalHandles, "globalhandles", "(Global handles)") \ - V(kEternalHandles, "eternalhandles", "(Eternal handles)") \ V(kThreadManager, "threadmanager", "(Thread manager)") \ V(kExtensions, "Extensions", "(Extensions)") diff --git a/chromium/v8/src/optimizing-compiler-thread.cc b/chromium/v8/src/optimizing-compiler-thread.cc index 337ddd4b2d2..21ef2371071 100644 --- a/chromium/v8/src/optimizing-compiler-thread.cc +++ b/chromium/v8/src/optimizing-compiler-thread.cc @@ -60,25 +60,12 @@ void OptimizingCompilerThread::Run() { OS::Sleep(FLAG_parallel_recompilation_delay); } - switch (static_cast<StopFlag>(Acquire_Load(&stop_thread_))) { - case CONTINUE: - break; - case STOP: - if (FLAG_trace_parallel_recompilation) { - time_spent_total_ = OS::Ticks() - epoch; - } - stop_semaphore_->Signal(); - return; - case FLUSH: - // The main thread is blocked, waiting for the stop semaphore. - { AllowHandleDereference allow_handle_dereference; - FlushInputQueue(true); - } - Release_Store(&queue_length_, static_cast<AtomicWord>(0)); - Release_Store(&stop_thread_, static_cast<AtomicWord>(CONTINUE)); - stop_semaphore_->Signal(); - // Return to start of consumer loop. - continue; + if (Acquire_Load(&stop_thread_)) { + stop_semaphore_->Signal(); + if (FLAG_trace_parallel_recompilation) { + time_spent_total_ = OS::Ticks() - epoch; + } + return; } int64_t compiling_start = 0; @@ -95,9 +82,7 @@ void OptimizingCompilerThread::Run() { void OptimizingCompilerThread::CompileNext() { OptimizingCompiler* optimizing_compiler = NULL; - bool result = input_queue_.Dequeue(&optimizing_compiler); - USE(result); - ASSERT(result); + input_queue_.Dequeue(&optimizing_compiler); Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(-1)); // The function may have already been optimized by OSR. Simply continue. @@ -117,61 +102,26 @@ void OptimizingCompilerThread::CompileNext() { } -void OptimizingCompilerThread::FlushInputQueue(bool restore_function_code) { - OptimizingCompiler* optimizing_compiler; - // The optimizing compiler is allocated in the CompilationInfo's zone. - while (input_queue_.Dequeue(&optimizing_compiler)) { - // This should not block, since we have one signal on the input queue - // semaphore corresponding to each element in the input queue. - input_queue_semaphore_->Wait(); - CompilationInfo* info = optimizing_compiler->info(); - if (restore_function_code) { - Handle<JSFunction> function = info->closure(); - function->ReplaceCode(function->shared()->code()); - } - delete info; - } -} - - -void OptimizingCompilerThread::FlushOutputQueue(bool restore_function_code) { - OptimizingCompiler* optimizing_compiler; - // The optimizing compiler is allocated in the CompilationInfo's zone. - while (output_queue_.Dequeue(&optimizing_compiler)) { - CompilationInfo* info = optimizing_compiler->info(); - if (restore_function_code) { - Handle<JSFunction> function = info->closure(); - function->ReplaceCode(function->shared()->code()); - } - delete info; - } -} - - -void OptimizingCompilerThread::Flush() { - ASSERT(!IsOptimizerThread()); - Release_Store(&stop_thread_, static_cast<AtomicWord>(FLUSH)); - input_queue_semaphore_->Signal(); - stop_semaphore_->Wait(); - FlushOutputQueue(true); -} - - void OptimizingCompilerThread::Stop() { ASSERT(!IsOptimizerThread()); - Release_Store(&stop_thread_, static_cast<AtomicWord>(STOP)); + Release_Store(&stop_thread_, static_cast<AtomicWord>(true)); input_queue_semaphore_->Signal(); stop_semaphore_->Wait(); if (FLAG_parallel_recompilation_delay != 0) { // Barrier when loading queue length is not necessary since the write // happens in CompileNext on the same thread. - // This is used only for testing. while (NoBarrier_Load(&queue_length_) > 0) CompileNext(); InstallOptimizedFunctions(); } else { - FlushInputQueue(false); - FlushOutputQueue(false); + OptimizingCompiler* optimizing_compiler; + // The optimizing compiler is allocated in the CompilationInfo's zone. + while (input_queue_.Dequeue(&optimizing_compiler)) { + delete optimizing_compiler->info(); + } + while (output_queue_.Dequeue(&optimizing_compiler)) { + delete optimizing_compiler->info(); + } } if (FLAG_trace_parallel_recompilation) { diff --git a/chromium/v8/src/optimizing-compiler-thread.h b/chromium/v8/src/optimizing-compiler-thread.h index cbd4d0e4872..275ceb40b71 100644 --- a/chromium/v8/src/optimizing-compiler-thread.h +++ b/chromium/v8/src/optimizing-compiler-thread.h @@ -54,13 +54,13 @@ class OptimizingCompilerThread : public Thread { install_mutex_(OS::CreateMutex()), time_spent_compiling_(0), time_spent_total_(0) { - NoBarrier_Store(&stop_thread_, static_cast<AtomicWord>(CONTINUE)); + NoBarrier_Store(&stop_thread_, static_cast<AtomicWord>(false)); NoBarrier_Store(&queue_length_, static_cast<AtomicWord>(0)); } void Run(); void Stop(); - void Flush(); + void CompileNext(); void QueueForOptimization(OptimizingCompiler* optimizing_compiler); void InstallOptimizedFunctions(); @@ -92,13 +92,6 @@ class OptimizingCompilerThread : public Thread { } private: - enum StopFlag { CONTINUE, STOP, FLUSH }; - - void FlushInputQueue(bool restore_function_code); - void FlushOutputQueue(bool restore_function_code); - - void CompileNext(); - #ifdef DEBUG int thread_id_; Mutex* thread_id_mutex_; diff --git a/chromium/v8/src/parser.cc b/chromium/v8/src/parser.cc index 4947790395f..df568ef1bbb 100644 --- a/chromium/v8/src/parser.cc +++ b/chromium/v8/src/parser.cc @@ -3197,20 +3197,6 @@ Expression* Parser::ParseUnaryExpression(bool* ok) { factory()->NewNumberLiteral(1), position); } - // The same idea for '-foo' => 'foo*(-1)'. - if (op == Token::SUB) { - return factory()->NewBinaryOperation(Token::MUL, - expression, - factory()->NewNumberLiteral(-1), - position); - } - // ...and one more time for '~foo' => 'foo^(~0)'. - if (op == Token::BIT_NOT) { - return factory()->NewBinaryOperation(Token::BIT_XOR, - expression, - factory()->NewNumberLiteral(~0), - position); - } return factory()->NewUnaryOperation(op, expression, position); diff --git a/chromium/v8/src/platform-linux.cc b/chromium/v8/src/platform-linux.cc index 885683398e2..5c252bbf884 100644 --- a/chromium/v8/src/platform-linux.cc +++ b/chromium/v8/src/platform-linux.cc @@ -239,8 +239,7 @@ bool OS::ArmUsingHardFloat() { #else #if defined(__ARM_PCS_VFP) return true; -#elif defined(__ARM_PCS) || defined(__SOFTFP__) || defined(__SOFTFP) || \ - !defined(__VFP_FP__) +#elif defined(__ARM_PCS) || defined(__SOFTFP) || !defined(__VFP_FP__) return false; #else #error "Your version of GCC does not report the FP ABI compiled for." \ diff --git a/chromium/v8/src/profile-generator-inl.h b/chromium/v8/src/profile-generator-inl.h index 6791c88c56e..d92085ac32d 100644 --- a/chromium/v8/src/profile-generator-inl.h +++ b/chromium/v8/src/profile-generator-inl.h @@ -92,8 +92,6 @@ CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { case OTHER: case EXTERNAL: return program_entry_; - case IDLE: - return idle_entry_; default: return NULL; } } diff --git a/chromium/v8/src/profile-generator.cc b/chromium/v8/src/profile-generator.cc index 86bd17b70a0..e772a546471 100644 --- a/chromium/v8/src/profile-generator.cc +++ b/chromium/v8/src/profile-generator.cc @@ -220,7 +220,7 @@ double ProfileNode::GetTotalMillis() const { void ProfileNode::Print(int indent) { - OS::Print("%5u %5u %*c %s%s %d #%d", + OS::Print("%5u %5u %*c %s%s #%d %d", total_ticks_, self_ticks_, indent, ' ', entry_->name_prefix(), @@ -614,8 +614,6 @@ const char* const ProfileGenerator::kAnonymousFunctionName = "(anonymous function)"; const char* const ProfileGenerator::kProgramEntryName = "(program)"; -const char* const ProfileGenerator::kIdleEntryName = - "(idle)"; const char* const ProfileGenerator::kGarbageCollectorEntryName = "(garbage collector)"; const char* const ProfileGenerator::kUnresolvedFunctionName = @@ -626,8 +624,6 @@ ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) : profiles_(profiles), program_entry_( profiles->NewCodeEntry(Logger::FUNCTION_TAG, kProgramEntryName)), - idle_entry_( - profiles->NewCodeEntry(Logger::FUNCTION_TAG, kIdleEntryName)), gc_entry_( profiles->NewCodeEntry(Logger::BUILTIN_TAG, kGarbageCollectorEntryName)), diff --git a/chromium/v8/src/profile-generator.h b/chromium/v8/src/profile-generator.h index 99aeb1f5c7f..0cc397ed9bf 100644 --- a/chromium/v8/src/profile-generator.h +++ b/chromium/v8/src/profile-generator.h @@ -342,7 +342,6 @@ class ProfileGenerator { static const char* const kAnonymousFunctionName; static const char* const kProgramEntryName; - static const char* const kIdleEntryName; static const char* const kGarbageCollectorEntryName; // Used to represent frames for which we have no reliable way to // detect function. @@ -354,7 +353,6 @@ class ProfileGenerator { CpuProfilesCollection* profiles_; CodeMap code_map_; CodeEntry* program_entry_; - CodeEntry* idle_entry_; CodeEntry* gc_entry_; CodeEntry* unresolved_entry_; diff --git a/chromium/v8/src/runtime.cc b/chromium/v8/src/runtime.cc index 10de6f9e5ec..ef6eeb3a497 100644 --- a/chromium/v8/src/runtime.cc +++ b/chromium/v8/src/runtime.cc @@ -66,30 +66,6 @@ #include "v8threads.h" #include "vm-state-inl.h" -#ifdef V8_I18N_SUPPORT -#include "i18n.h" -#include "unicode/brkiter.h" -#include "unicode/calendar.h" -#include "unicode/coll.h" -#include "unicode/curramt.h" -#include "unicode/datefmt.h" -#include "unicode/dcfmtsym.h" -#include "unicode/decimfmt.h" -#include "unicode/dtfmtsym.h" -#include "unicode/dtptngen.h" -#include "unicode/locid.h" -#include "unicode/numfmt.h" -#include "unicode/numsys.h" -#include "unicode/smpdtfmt.h" -#include "unicode/timezone.h" -#include "unicode/uchar.h" -#include "unicode/ucol.h" -#include "unicode/ucurr.h" -#include "unicode/uloc.h" -#include "unicode/unum.h" -#include "unicode/uversion.h" -#endif - #ifndef _STLP_VENDOR_CSTD // STLPort doesn't import fpclassify and isless into the std namespace. using std::fpclassify; @@ -3020,7 +2996,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ResumeJSGeneratorObject) { JavaScriptFrame* frame = stack_iterator.frame(); ASSERT_EQ(frame->function(), generator_object->function()); - ASSERT(frame->function()->is_compiled()); STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting <= 0); STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed <= 0); @@ -7261,6 +7236,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) { } +RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) { + SealHandleScope shs(isolate); + ASSERT(args.length() == 1); + + CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); + return isolate->heap()->NumberFromInt32(~x); +} + + RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) { SealHandleScope shs(isolate); ASSERT(args.length() == 2); @@ -8495,7 +8479,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) { } CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); if (FLAG_parallel_recompilation && sync_with_compiler_thread) { - while (function->IsInRecompileQueue() || + while (function->IsMarkedForParallelRecompilation() || + function->IsInRecompileQueue() || function->IsMarkedForInstallingRecompiledCode()) { isolate->optimizing_compiler_thread()->InstallOptimizedFunctions(); OS::Sleep(50); @@ -8562,21 +8547,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) { // Use linear search of the unoptimized code's back edge table to find // the AST id matching the PC. - uint32_t target_pc_offset = - static_cast<uint32_t>(frame->pc() - unoptimized->instruction_start()); + Address start = unoptimized->instruction_start(); + unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start); + Address table_cursor = start + unoptimized->back_edge_table_offset(); + uint32_t table_length = Memory::uint32_at(table_cursor); + table_cursor += kIntSize; uint32_t loop_depth = 0; - - for (FullCodeGenerator::BackEdgeTableIterator back_edges(*unoptimized); - !back_edges.Done(); - back_edges.Next()) { - if (back_edges.pc_offset() == target_pc_offset) { - ast_id = back_edges.ast_id(); - loop_depth = back_edges.loop_depth(); + for (unsigned i = 0; i < table_length; ++i) { + // Table entries are (AST id, pc offset) pairs. + uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize); + if (pc_offset == target_pc_offset) { + ast_id = BailoutId(static_cast<int>(Memory::uint32_at(table_cursor))); + loop_depth = Memory::uint32_at(table_cursor + 2 * kIntSize); break; } + table_cursor += FullCodeGenerator::kBackEdgeEntrySize; } ASSERT(!ast_id.IsNone()); - if (FLAG_trace_osr) { PrintF("[replacing on-stack at AST id %d, loop depth %d in ", ast_id.ToInt(), loop_depth); @@ -8693,8 +8680,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) { CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2); CONVERT_SMI_ARG_CHECKED(offset, 3); CONVERT_SMI_ARG_CHECKED(argc, 4); - RUNTIME_ASSERT(offset >= 0); - RUNTIME_ASSERT(argc >= 0); + ASSERT(offset >= 0); + ASSERT(argc >= 0); // If there are too many arguments, allocate argv via malloc. const int argv_small_size = 10; @@ -9487,7 +9474,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) { ASSERT_EQ(1, args.length()); CONVERT_ARG_HANDLE_CHECKED(String, source, 0); - source = Handle<String>(FlattenGetString(source)); + source = Handle<String>(source->TryFlattenGetString()); // Optimized fast case where we only have ASCII characters. Handle<Object> result; if (source->IsSeqOneByteString()) { @@ -11227,7 +11214,6 @@ static Handle<JSObject> MaterializeStackLocalsWithFrameInspector( ? frame_inspector->GetParameter(i) : isolate->heap()->undefined_value(), isolate); - ASSERT(!value->IsTheHole()); RETURN_IF_EMPTY_HANDLE_VALUE( isolate, @@ -11242,15 +11228,12 @@ static Handle<JSObject> MaterializeStackLocalsWithFrameInspector( // Second fill all stack locals. for (int i = 0; i < scope_info->StackLocalCount(); ++i) { - Handle<Object> value(frame_inspector->GetExpression(i), isolate); - if (value->IsTheHole()) continue; - RETURN_IF_EMPTY_HANDLE_VALUE( isolate, SetProperty(isolate, target, Handle<String>(scope_info->StackLocalName(i)), - value, + Handle<Object>(frame_inspector->GetExpression(i), isolate), NONE, kNonStrictMode), Handle<JSObject>()); @@ -11277,7 +11260,6 @@ static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate, // Parameters. for (int i = 0; i < scope_info->ParameterCount(); ++i) { - ASSERT(!frame->GetParameter(i)->IsTheHole()); HandleScope scope(isolate); Handle<Object> value = GetProperty( isolate, target, Handle<String>(scope_info->ParameterName(i))); @@ -11286,7 +11268,6 @@ static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate, // Stack locals. for (int i = 0; i < scope_info->StackLocalCount(); ++i) { - if (frame->GetExpression(i)->IsTheHole()) continue; HandleScope scope(isolate); Handle<Object> value = GetProperty( isolate, target, Handle<String>(scope_info->StackLocalName(i))); @@ -12021,15 +12002,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetStepInPositions) { JavaScriptFrameIterator frame_it(isolate, id); JavaScriptFrame* frame = frame_it.frame(); - Handle<JSFunction> fun = - Handle<JSFunction>(frame->function()); Handle<SharedFunctionInfo> shared = - Handle<SharedFunctionInfo>(fun->shared()); - - if (!isolate->debug()->EnsureDebugInfo(shared, fun)) { - return isolate->heap()->undefined_value(); - } - + Handle<SharedFunctionInfo>(frame->function()->shared()); Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared); int len = 0; @@ -12042,14 +12016,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetStepInPositions) { int current_statement_pos = break_location_iterator.statement_position(); while (!break_location_iterator.Done()) { - if (break_location_iterator.pc() > frame->pc()) { - if (break_location_iterator.IsStepInLocation(isolate)) { - Smi* position_value = Smi::FromInt(break_location_iterator.position()); - JSObject::SetElement(array, len, - Handle<Object>(position_value, isolate), - NONE, kNonStrictMode); - len++; - } + if (break_location_iterator.IsStepInLocation(isolate)) { + Smi* position_value = Smi::FromInt(break_location_iterator.position()); + JSObject::SetElement(array, len, + Handle<Object>(position_value, isolate), + NONE, kNonStrictMode); + len++; } // Advance iterator. break_location_iterator.Next(); @@ -13392,489 +13364,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) { #endif // ENABLE_DEBUGGER_SUPPORT -#ifdef V8_I18N_SUPPORT -RUNTIME_FUNCTION(MaybeObject*, Runtime_CanonicalizeLanguageTag) { - HandleScope scope(isolate); - - ASSERT(args.length() == 1); - CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0); - - v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str)); - - // Return value which denotes invalid language tag. - const char* const kInvalidTag = "invalid-tag"; - - UErrorCode error = U_ZERO_ERROR; - char icu_result[ULOC_FULLNAME_CAPACITY]; - int icu_length = 0; - - uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY, - &icu_length, &error); - if (U_FAILURE(error) || icu_length == 0) { - return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag)); - } - - char result[ULOC_FULLNAME_CAPACITY]; - - // Force strict BCP47 rules. - uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error); - - if (U_FAILURE(error)) { - return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag)); - } - - return isolate->heap()->AllocateStringFromOneByte(CStrVector(result)); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_AvailableLocalesOf) { - HandleScope scope(isolate); - - ASSERT(args.length() == 1); - CONVERT_ARG_HANDLE_CHECKED(String, service, 0); - - const icu::Locale* available_locales = NULL; - int32_t count = 0; - - if (service->IsUtf8EqualTo(CStrVector("collator"))) { - available_locales = icu::Collator::getAvailableLocales(count); - } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) { - available_locales = icu::NumberFormat::getAvailableLocales(count); - } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) { - available_locales = icu::DateFormat::getAvailableLocales(count); - } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) { - available_locales = icu::BreakIterator::getAvailableLocales(count); - } - - UErrorCode error = U_ZERO_ERROR; - char result[ULOC_FULLNAME_CAPACITY]; - Handle<JSObject> locales = - isolate->factory()->NewJSObject(isolate->object_function()); - - for (int32_t i = 0; i < count; ++i) { - const char* icu_name = available_locales[i].getName(); - - error = U_ZERO_ERROR; - // No need to force strict BCP47 rules. - uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error); - if (U_FAILURE(error)) { - // This shouldn't happen, but lets not break the user. - continue; - } - - RETURN_IF_EMPTY_HANDLE(isolate, - JSObject::SetLocalPropertyIgnoreAttributes( - locales, - isolate->factory()->NewStringFromAscii(CStrVector(result)), - isolate->factory()->NewNumber(i), - NONE)); - } - - return *locales; -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultICULocale) { - SealHandleScope shs(isolate); - - ASSERT(args.length() == 0); - - icu::Locale default_locale; - - // Set the locale - char result[ULOC_FULLNAME_CAPACITY]; - UErrorCode status = U_ZERO_ERROR; - uloc_toLanguageTag( - default_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status); - if (U_SUCCESS(status)) { - return isolate->heap()->AllocateStringFromOneByte(CStrVector(result)); - } - - return isolate->heap()->AllocateStringFromOneByte(CStrVector("und")); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLanguageTagVariants) { - HandleScope scope(isolate); - - ASSERT(args.length() == 1); - - CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0); - - uint32_t length = static_cast<uint32_t>(input->length()->Number()); - Handle<FixedArray> output = isolate->factory()->NewFixedArray(length); - Handle<Name> maximized = - isolate->factory()->NewStringFromAscii(CStrVector("maximized")); - Handle<Name> base = - isolate->factory()->NewStringFromAscii(CStrVector("base")); - for (unsigned int i = 0; i < length; ++i) { - MaybeObject* maybe_string = input->GetElement(i); - Object* locale_id; - if (!maybe_string->ToObject(&locale_id) || !locale_id->IsString()) { - return isolate->Throw(isolate->heap()->illegal_argument_string()); - } - - v8::String::Utf8Value utf8_locale_id( - v8::Utils::ToLocal(Handle<String>(String::cast(locale_id)))); - - UErrorCode error = U_ZERO_ERROR; - - // Convert from BCP47 to ICU format. - // de-DE-u-co-phonebk -> de_DE@collation=phonebook - char icu_locale[ULOC_FULLNAME_CAPACITY]; - int icu_locale_length = 0; - uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY, - &icu_locale_length, &error); - if (U_FAILURE(error) || icu_locale_length == 0) { - return isolate->Throw(isolate->heap()->illegal_argument_string()); - } - - // Maximize the locale. - // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook - char icu_max_locale[ULOC_FULLNAME_CAPACITY]; - uloc_addLikelySubtags( - icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY, &error); - - // Remove extensions from maximized locale. - // de_Latn_DE@collation=phonebook -> de_Latn_DE - char icu_base_max_locale[ULOC_FULLNAME_CAPACITY]; - uloc_getBaseName( - icu_max_locale, icu_base_max_locale, ULOC_FULLNAME_CAPACITY, &error); - - // Get original name without extensions. - // de_DE@collation=phonebook -> de_DE - char icu_base_locale[ULOC_FULLNAME_CAPACITY]; - uloc_getBaseName( - icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY, &error); - - // Convert from ICU locale format to BCP47 format. - // de_Latn_DE -> de-Latn-DE - char base_max_locale[ULOC_FULLNAME_CAPACITY]; - uloc_toLanguageTag(icu_base_max_locale, base_max_locale, - ULOC_FULLNAME_CAPACITY, FALSE, &error); - - // de_DE -> de-DE - char base_locale[ULOC_FULLNAME_CAPACITY]; - uloc_toLanguageTag( - icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY, FALSE, &error); - - if (U_FAILURE(error)) { - return isolate->Throw(isolate->heap()->illegal_argument_string()); - } - - Handle<JSObject> result = - isolate->factory()->NewJSObject(isolate->object_function()); - RETURN_IF_EMPTY_HANDLE(isolate, - JSObject::SetLocalPropertyIgnoreAttributes( - result, - maximized, - isolate->factory()->NewStringFromAscii(CStrVector(base_max_locale)), - NONE)); - RETURN_IF_EMPTY_HANDLE(isolate, - JSObject::SetLocalPropertyIgnoreAttributes( - result, - base, - isolate->factory()->NewStringFromAscii(CStrVector(base_locale)), - NONE)); - output->set(i, *result); - } - - Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(output); - result->set_length(Smi::FromInt(length)); - return *result; -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateDateTimeFormat) { - HandleScope scope(isolate); - - ASSERT(args.length() == 3); - - CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); - CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); - CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); - - Handle<ObjectTemplateInfo> date_format_template = - I18N::GetTemplate(isolate); - - // Create an empty object wrapper. - bool has_pending_exception = false; - Handle<JSObject> local_object = Execution::InstantiateObject( - date_format_template, &has_pending_exception); - if (has_pending_exception) { - ASSERT(isolate->has_pending_exception()); - return Failure::Exception(); - } - - // Set date time formatter as internal field of the resulting JS object. - icu::SimpleDateFormat* date_format = DateFormat::InitializeDateTimeFormat( - isolate, locale, options, resolved); - - if (!date_format) return isolate->ThrowIllegalOperation(); - - local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format)); - - RETURN_IF_EMPTY_HANDLE(isolate, - JSObject::SetLocalPropertyIgnoreAttributes( - local_object, - isolate->factory()->NewStringFromAscii(CStrVector("dateFormat")), - isolate->factory()->NewStringFromAscii(CStrVector("valid")), - NONE)); - - Persistent<v8::Object> wrapper(reinterpret_cast<v8::Isolate*>(isolate), - v8::Utils::ToLocal(local_object)); - // Make object handle weak so we can delete the data format once GC kicks in. - wrapper.MakeWeak<void>(NULL, &DateFormat::DeleteDateFormat); - wrapper.ClearAndLeak(); - return *local_object; -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateFormat) { - HandleScope scope(isolate); - - ASSERT(args.length() == 2); - - CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0); - CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1); - - bool has_pending_exception = false; - double millis = Execution::ToNumber(date, &has_pending_exception)->Number(); - if (has_pending_exception) { - ASSERT(isolate->has_pending_exception()); - return Failure::Exception(); - } - - icu::SimpleDateFormat* date_format = - DateFormat::UnpackDateFormat(isolate, date_format_holder); - if (!date_format) return isolate->ThrowIllegalOperation(); - - icu::UnicodeString result; - date_format->format(millis, result); - - return *isolate->factory()->NewStringFromTwoByte( - Vector<const uint16_t>( - reinterpret_cast<const uint16_t*>(result.getBuffer()), - result.length())); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateParse) { - HandleScope scope(isolate); - - ASSERT(args.length() == 2); - - CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0); - CONVERT_ARG_HANDLE_CHECKED(String, date_string, 1); - - v8::String::Utf8Value utf8_date(v8::Utils::ToLocal(date_string)); - icu::UnicodeString u_date(icu::UnicodeString::fromUTF8(*utf8_date)); - icu::SimpleDateFormat* date_format = - DateFormat::UnpackDateFormat(isolate, date_format_holder); - if (!date_format) return isolate->ThrowIllegalOperation(); - - UErrorCode status = U_ZERO_ERROR; - UDate date = date_format->parse(u_date, status); - if (U_FAILURE(status)) return isolate->heap()->undefined_value(); - - bool has_pending_exception = false; - Handle<JSDate> result = Handle<JSDate>::cast( - Execution::NewDate(static_cast<double>(date), &has_pending_exception)); - if (has_pending_exception) { - ASSERT(isolate->has_pending_exception()); - return Failure::Exception(); - } - return *result; -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateNumberFormat) { - HandleScope scope(isolate); - - ASSERT(args.length() == 3); - - CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); - CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); - CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); - - Handle<ObjectTemplateInfo> number_format_template = - I18N::GetTemplate(isolate); - - // Create an empty object wrapper. - bool has_pending_exception = false; - Handle<JSObject> local_object = Execution::InstantiateObject( - number_format_template, &has_pending_exception); - if (has_pending_exception) { - ASSERT(isolate->has_pending_exception()); - return Failure::Exception(); - } - - // Set number formatter as internal field of the resulting JS object. - icu::DecimalFormat* number_format = NumberFormat::InitializeNumberFormat( - isolate, locale, options, resolved); - - if (!number_format) return isolate->ThrowIllegalOperation(); - - local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format)); - - RETURN_IF_EMPTY_HANDLE(isolate, - JSObject::SetLocalPropertyIgnoreAttributes( - local_object, - isolate->factory()->NewStringFromAscii(CStrVector("numberFormat")), - isolate->factory()->NewStringFromAscii(CStrVector("valid")), - NONE)); - - Persistent<v8::Object> wrapper(reinterpret_cast<v8::Isolate*>(isolate), - v8::Utils::ToLocal(local_object)); - // Make object handle weak so we can delete the number format once GC kicks - // in. - wrapper.MakeWeak<void>(NULL, &NumberFormat::DeleteNumberFormat); - wrapper.ClearAndLeak(); - return *local_object; -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberFormat) { - HandleScope scope(isolate); - - ASSERT(args.length() == 2); - - CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0); - CONVERT_ARG_HANDLE_CHECKED(Object, number, 1); - - bool has_pending_exception = false; - double value = Execution::ToNumber(number, &has_pending_exception)->Number(); - if (has_pending_exception) { - ASSERT(isolate->has_pending_exception()); - return Failure::Exception(); - } - - icu::DecimalFormat* number_format = - NumberFormat::UnpackNumberFormat(isolate, number_format_holder); - if (!number_format) return isolate->ThrowIllegalOperation(); - - icu::UnicodeString result; - number_format->format(value, result); - - return *isolate->factory()->NewStringFromTwoByte( - Vector<const uint16_t>( - reinterpret_cast<const uint16_t*>(result.getBuffer()), - result.length())); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberParse) { - HandleScope scope(isolate); - - ASSERT(args.length() == 2); - - CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0); - CONVERT_ARG_HANDLE_CHECKED(String, number_string, 1); - - v8::String::Utf8Value utf8_number(v8::Utils::ToLocal(number_string)); - icu::UnicodeString u_number(icu::UnicodeString::fromUTF8(*utf8_number)); - icu::DecimalFormat* number_format = - NumberFormat::UnpackNumberFormat(isolate, number_format_holder); - if (!number_format) return isolate->ThrowIllegalOperation(); - - UErrorCode status = U_ZERO_ERROR; - icu::Formattable result; - // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49 - // to be part of Chrome. - // TODO(cira): Include currency parsing code using parseCurrency call. - // We need to check if the formatter parses all currencies or only the - // one it was constructed with (it will impact the API - how to return ISO - // code and the value). - number_format->parse(u_number, result, status); - if (U_FAILURE(status)) return isolate->heap()->undefined_value(); - - switch (result.getType()) { - case icu::Formattable::kDouble: - return *isolate->factory()->NewNumber(result.getDouble()); - case icu::Formattable::kLong: - return *isolate->factory()->NewNumberFromInt(result.getLong()); - case icu::Formattable::kInt64: - return *isolate->factory()->NewNumber( - static_cast<double>(result.getInt64())); - default: - return isolate->heap()->undefined_value(); - } -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCollator) { - HandleScope scope(isolate); - - ASSERT(args.length() == 3); - - CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); - CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); - CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); - - Handle<ObjectTemplateInfo> collator_template = I18N::GetTemplate(isolate); - - // Create an empty object wrapper. - bool has_pending_exception = false; - Handle<JSObject> local_object = Execution::InstantiateObject( - collator_template, &has_pending_exception); - if (has_pending_exception) { - ASSERT(isolate->has_pending_exception()); - return Failure::Exception(); - } - - // Set collator as internal field of the resulting JS object. - icu::Collator* collator = Collator::InitializeCollator( - isolate, locale, options, resolved); - - if (!collator) return isolate->ThrowIllegalOperation(); - - local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator)); - - RETURN_IF_EMPTY_HANDLE(isolate, - JSObject::SetLocalPropertyIgnoreAttributes( - local_object, - isolate->factory()->NewStringFromAscii(CStrVector("collator")), - isolate->factory()->NewStringFromAscii(CStrVector("valid")), - NONE)); - - Persistent<v8::Object> wrapper(reinterpret_cast<v8::Isolate*>(isolate), - v8::Utils::ToLocal(local_object)); - // Make object handle weak so we can delete the collator once GC kicks in. - wrapper.MakeWeak<void>(NULL, &Collator::DeleteCollator); - wrapper.ClearAndLeak(); - return *local_object; -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalCompare) { - HandleScope scope(isolate); - - ASSERT(args.length() == 3); - - CONVERT_ARG_HANDLE_CHECKED(JSObject, collator_holder, 0); - CONVERT_ARG_HANDLE_CHECKED(String, string1, 1); - CONVERT_ARG_HANDLE_CHECKED(String, string2, 2); - - icu::Collator* collator = Collator::UnpackCollator(isolate, collator_holder); - if (!collator) return isolate->ThrowIllegalOperation(); - - v8::String::Value string_value1(v8::Utils::ToLocal(string1)); - v8::String::Value string_value2(v8::Utils::ToLocal(string2)); - const UChar* u_string1 = reinterpret_cast<const UChar*>(*string_value1); - const UChar* u_string2 = reinterpret_cast<const UChar*>(*string_value2); - UErrorCode status = U_ZERO_ERROR; - UCollationResult result = collator->compare(u_string1, - string_value1.length(), - u_string2, - string_value2.length(), - status); - if (U_FAILURE(status)) return isolate->ThrowIllegalOperation(); - - return *isolate->factory()->NewNumberFromInt(result); -} -#endif // V8_I18N_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 @@ -13993,18 +13482,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FlattenString) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_MigrateInstance) { - HandleScope scope(isolate); - ASSERT(args.length() == 1); - CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); - if (!object->IsJSObject()) return Smi::FromInt(0); - Handle<JSObject> js_object = Handle<JSObject>::cast(object); - if (!js_object->map()->is_deprecated()) return Smi::FromInt(0); - JSObject::MigrateInstance(js_object); - return *object; -} - - RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) { SealHandleScope shs(isolate); // This is only called from codegen, so checks might be more lax. @@ -14248,9 +13725,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetIsObserved) { ASSERT(proto->IsJSGlobalObject()); obj = JSReceiver::cast(proto); } - if (obj->IsJSProxy()) - return isolate->heap()->undefined_value(); - ASSERT(!(obj->map()->is_observed() && obj->IsJSObject() && JSObject::cast(obj)->HasFastElements())); ASSERT(obj->IsJSObject()); diff --git a/chromium/v8/src/runtime.h b/chromium/v8/src/runtime.h index 23e91f2ae9e..398cb3bcc24 100644 --- a/chromium/v8/src/runtime.h +++ b/chromium/v8/src/runtime.h @@ -109,7 +109,6 @@ namespace internal { F(DebugCallbackSupportsStepping, 1, 1) \ F(DebugPrepareStepInIfStepping, 1, 1) \ F(FlattenString, 1, 1) \ - F(MigrateInstance, 1, 1) \ \ /* Array join support */ \ F(PushIfAbsent, 2, 1) \ @@ -158,6 +157,7 @@ namespace internal { F(NumberOr, 2, 1) \ F(NumberAnd, 2, 1) \ F(NumberXor, 2, 1) \ + F(NumberNot, 1, 1) \ \ F(NumberShl, 2, 1) \ F(NumberShr, 2, 1) \ @@ -534,35 +534,6 @@ namespace internal { #define RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F) #endif - -#ifdef V8_I18N_SUPPORT -#define RUNTIME_FUNCTION_LIST_I18N_SUPPORT(F) \ - /* i18n support */ \ - /* Standalone, helper methods. */ \ - F(CanonicalizeLanguageTag, 1, 1) \ - F(AvailableLocalesOf, 1, 1) \ - F(GetDefaultICULocale, 0, 1) \ - F(GetLanguageTagVariants, 1, 1) \ - \ - /* Date format and parse. */ \ - F(CreateDateTimeFormat, 3, 1) \ - F(InternalDateFormat, 2, 1) \ - F(InternalDateParse, 2, 1) \ - \ - /* Number format and parse. */ \ - F(CreateNumberFormat, 3, 1) \ - F(InternalNumberFormat, 2, 1) \ - F(InternalNumberParse, 2, 1) \ - \ - /* Collator. */ \ - F(CreateCollator, 3, 1) \ - F(InternalCompare, 3, 1) \ - -#else -#define RUNTIME_FUNCTION_LIST_I18N_SUPPORT(F) -#endif - - #ifdef DEBUG #define RUNTIME_FUNCTION_LIST_DEBUG(F) \ /* Testing */ \ @@ -580,8 +551,7 @@ namespace internal { RUNTIME_FUNCTION_LIST_ALWAYS_1(F) \ RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \ RUNTIME_FUNCTION_LIST_DEBUG(F) \ - RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F) \ - RUNTIME_FUNCTION_LIST_I18N_SUPPORT(F) + RUNTIME_FUNCTION_LIST_DEBUGGER_SUPPORT(F) // ---------------------------------------------------------------------------- // INLINE_FUNCTION_LIST defines all inlined functions accessed diff --git a/chromium/v8/src/runtime.js b/chromium/v8/src/runtime.js index 5339570ef6e..90fb36b4223 100644 --- a/chromium/v8/src/runtime.js +++ b/chromium/v8/src/runtime.js @@ -294,6 +294,20 @@ function BIT_XOR(y) { } +// ECMA-262, section 11.4.7, page 47. +function UNARY_MINUS() { + var x = IS_NUMBER(this) ? this : %NonNumberToNumber(this); + return %NumberUnaryMinus(x); +} + + +// ECMA-262, section 11.4.8, page 48. +function BIT_NOT() { + var x = IS_NUMBER(this) ? this : %NonNumberToNumber(this); + return %NumberNot(x); +} + + // ECMA-262, section 11.7.1, page 51. function SHL(y) { var x = IS_NUMBER(this) ? this : %NonNumberToNumber(this); diff --git a/chromium/v8/src/sampler.cc b/chromium/v8/src/sampler.cc index 1d0cdedd1fc..d72ed1acdb8 100644 --- a/chromium/v8/src/sampler.cc +++ b/chromium/v8/src/sampler.cc @@ -38,10 +38,7 @@ #include <signal.h> #include <sys/time.h> #include <sys/syscall.h> -// OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h> -// and is a typedef for struct sigcontext. There is no uc_mcontext. -#if (!defined(__ANDROID__) || defined(__BIONIC_HAVE_UCONTEXT_T)) \ - && !defined(__OpenBSD__) +#if !defined(__ANDROID__) || defined(__BIONIC_HAVE_UCONTEXT_T) #include <ucontext.h> #endif #include <unistd.h> @@ -333,9 +330,7 @@ void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, #else // Extracting the sample from the context is extremely machine dependent. ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); -#if !defined(__OpenBSD__) mcontext_t& mcontext = ucontext->uc_mcontext; -#endif #if defined(__linux__) || defined(__ANDROID__) #if V8_HOST_ARCH_IA32 state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]); @@ -389,6 +384,7 @@ void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]); #endif // V8_HOST_ARCH_* #elif defined(__OpenBSD__) + USE(mcontext); #if V8_HOST_ARCH_IA32 state.pc = reinterpret_cast<Address>(ucontext->sc_eip); state.sp = reinterpret_cast<Address>(ucontext->sc_esp); @@ -619,7 +615,8 @@ DISABLE_ASAN void TickSample::Init(Isolate* isolate, // Avoid collecting traces while doing GC. if (state == GC) return; - Address js_entry_sp = isolate->js_entry_sp(); + const Address js_entry_sp = + Isolate::js_entry_sp(isolate->thread_local_top()); if (js_entry_sp == 0) { // Not executing JS now. return; diff --git a/chromium/v8/src/serialize.cc b/chromium/v8/src/serialize.cc index 746c926653d..6c5a620a418 100644 --- a/chromium/v8/src/serialize.cc +++ b/chromium/v8/src/serialize.cc @@ -1304,7 +1304,6 @@ void StartupSerializer::SerializeStrongReferences() { // No active or weak handles. CHECK(isolate->handle_scope_implementer()->blocks()->is_empty()); CHECK_EQ(0, isolate->global_handles()->NumberOfWeakHandles()); - CHECK_EQ(0, isolate->eternal_handles()->NumberOfHandles()); // We don't support serializing installed extensions. CHECK(!isolate->has_installed_extensions()); diff --git a/chromium/v8/src/spaces.h b/chromium/v8/src/spaces.h index aa864b66ba5..b47452e421f 100644 --- a/chromium/v8/src/spaces.h +++ b/chromium/v8/src/spaces.h @@ -784,9 +784,8 @@ class Page : public MemoryChunk { // Maximum object size that fits in a page. Objects larger than that size // are allocated in large object space and are never moved in memory. This // also applies to new space allocation, since objects are never migrated - // from new space to large object space. Takes double alignment into account. - static const int kMaxNonCodeHeapObjectSize = - kNonCodeObjectAreaSize - kPointerSize; + // from new space to large object space. + static const int kMaxNonCodeHeapObjectSize = kNonCodeObjectAreaSize; // Page size mask. static const intptr_t kPageAlignmentMask = (1 << kPageSizeBits) - 1; diff --git a/chromium/v8/src/splay-tree-inl.h b/chromium/v8/src/splay-tree-inl.h index 42024756e9b..4eca71d1004 100644 --- a/chromium/v8/src/splay-tree-inl.h +++ b/chromium/v8/src/splay-tree-inl.h @@ -91,12 +91,6 @@ bool SplayTree<Config, Allocator>::FindInternal(const Key& key) { template<typename Config, class Allocator> -bool SplayTree<Config, Allocator>::Contains(const Key& key) { - return FindInternal(key); -} - - -template<typename Config, class Allocator> bool SplayTree<Config, Allocator>::Find(const Key& key, Locator* locator) { if (FindInternal(key)) { locator->bind(root_); @@ -299,10 +293,9 @@ void SplayTree<Config, Allocator>::ForEach(Callback* callback) { template <typename Config, class Allocator> template <class Callback> void SplayTree<Config, Allocator>::ForEachNode(Callback* callback) { - if (root_ == NULL) return; // Pre-allocate some space for tiny trees. List<Node*, Allocator> nodes_to_visit(10, allocator_); - nodes_to_visit.Add(root_, allocator_); + if (root_ != NULL) nodes_to_visit.Add(root_, allocator_); int pos = 0; while (pos < nodes_to_visit.length()) { Node* node = nodes_to_visit[pos++]; diff --git a/chromium/v8/src/splay-tree.h b/chromium/v8/src/splay-tree.h index f393027a82c..8844d8a8ffe 100644 --- a/chromium/v8/src/splay-tree.h +++ b/chromium/v8/src/splay-tree.h @@ -39,9 +39,9 @@ namespace internal { // // typedef Key: the key type // typedef Value: the value type -// static const Key kNoKey: the dummy key used when no key is set -// static Value kNoValue(): the dummy value used to initialize nodes -// static int (Compare)(Key& a, Key& b) -> {-1, 0, 1}: comparison function +// static const kNoKey: the dummy key used when no key is set +// static const kNoValue: the dummy value used to initialize nodes +// int (Compare)(Key& a, Key& b) -> {-1, 0, 1}: comparison function // // The tree is also parameterized by an allocation policy // (Allocator). The policy is used for allocating lists in the C free @@ -74,11 +74,6 @@ class SplayTree { UNREACHABLE(); } - AllocationPolicy allocator() { return allocator_; } - - // Checks if there is a mapping for the key. - bool Contains(const Key& key); - // Inserts the given key in this tree with the given value. Returns // true if a node was inserted, otherwise false. If found the locator // is enabled and provides access to the mapping for the key. @@ -109,9 +104,6 @@ class SplayTree { // Remove the node with the given key from the tree. bool Remove(const Key& key); - // Remove all keys from the tree. - void Clear() { ResetRoot(); } - bool is_empty() { return root_ == NULL; } // Perform the splay operation for the given key. Moves the node with diff --git a/chromium/v8/src/type-info.cc b/chromium/v8/src/type-info.cc index 336b459d6b7..769df07e4fa 100644 --- a/chromium/v8/src/type-info.cc +++ b/chromium/v8/src/type-info.cc @@ -384,6 +384,17 @@ void TypeFeedbackOracle::CompareType(TypeFeedbackId id, } +Handle<Type> TypeFeedbackOracle::UnaryType(TypeFeedbackId id) { + Handle<Object> object = GetInfo(id); + if (!object->IsCode()) { + return handle(Type::None(), isolate()); + } + Handle<Code> code = Handle<Code>::cast(object); + ASSERT(code->is_unary_op_stub()); + return UnaryOpStub(code->extended_extra_ic_state()).GetType(isolate()); +} + + void TypeFeedbackOracle::BinaryType(TypeFeedbackId id, Handle<Type>* left, Handle<Type>* right, @@ -647,6 +658,7 @@ void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) { } break; + case Code::UNARY_OP_IC: case Code::BINARY_OP_IC: case Code::COMPARE_IC: case Code::TO_BOOLEAN_IC: diff --git a/chromium/v8/src/type-info.h b/chromium/v8/src/type-info.h index 4b376c84bdc..1a7c67dfb88 100644 --- a/chromium/v8/src/type-info.h +++ b/chromium/v8/src/type-info.h @@ -297,6 +297,7 @@ class TypeFeedbackOracle: public ZoneObject { byte ToBooleanTypes(TypeFeedbackId id); // Get type information for arithmetic operations and compares. + Handle<Type> UnaryType(TypeFeedbackId id); void BinaryType(TypeFeedbackId id, Handle<Type>* left, Handle<Type>* right, diff --git a/chromium/v8/src/types.h b/chromium/v8/src/types.h index fc69c785295..b2eb60c6920 100644 --- a/chromium/v8/src/types.h +++ b/chromium/v8/src/types.h @@ -303,11 +303,6 @@ struct Bounds { explicit Bounds(Handle<Type> t) : lower(t), upper(t) {} Bounds(Type* t, Isolate* isl) : lower(t, isl), upper(t, isl) {} - // Unrestricted bounds. - static Bounds Unbounded(Isolate* isl) { - return Bounds(Type::None(), Type::Any(), isl); - } - // Meet: both b1 and b2 are known to hold. static Bounds Both(Bounds b1, Bounds b2, Isolate* isl) { return Bounds( diff --git a/chromium/v8/src/typing.cc b/chromium/v8/src/typing.cc index f8e2a7c206d..4220d2110db 100644 --- a/chromium/v8/src/typing.cc +++ b/chromium/v8/src/typing.cc @@ -40,8 +40,7 @@ AstTyper::AstTyper(CompilationInfo* info) Handle<Code>(info->closure()->shared()->code()), Handle<Context>(info->closure()->context()->native_context()), info->isolate(), - info->zone()), - store_(info->zone()) { + info->zone()) { InitializeAstVisitor(); } @@ -80,16 +79,12 @@ void AstTyper::VisitStatements(ZoneList<Statement*>* stmts) { for (int i = 0; i < stmts->length(); ++i) { Statement* stmt = stmts->at(i); RECURSE(Visit(stmt)); - if (stmt->IsJump()) break; } } void AstTyper::VisitBlock(Block* stmt) { RECURSE(VisitStatements(stmt->statements())); - if (stmt->labels() != NULL) { - store_.Forget(); // Control may transfer here via 'break l'. - } } @@ -103,41 +98,30 @@ void AstTyper::VisitEmptyStatement(EmptyStatement* stmt) { void AstTyper::VisitIfStatement(IfStatement* stmt) { - // Collect type feedback. + RECURSE(Visit(stmt->condition())); + RECURSE(Visit(stmt->then_statement())); + RECURSE(Visit(stmt->else_statement())); + if (!stmt->condition()->ToBooleanIsTrue() && !stmt->condition()->ToBooleanIsFalse()) { stmt->condition()->RecordToBooleanTypeFeedback(oracle()); } - - RECURSE(Visit(stmt->condition())); - Effects then_effects = EnterEffects(); - RECURSE(Visit(stmt->then_statement())); - ExitEffects(); - Effects else_effects = EnterEffects(); - RECURSE(Visit(stmt->else_statement())); - ExitEffects(); - then_effects.Alt(else_effects); - store_.Seq(then_effects); } void AstTyper::VisitContinueStatement(ContinueStatement* stmt) { - // TODO(rossberg): is it worth having a non-termination effect? } void AstTyper::VisitBreakStatement(BreakStatement* stmt) { - // TODO(rossberg): is it worth having a non-termination effect? } void AstTyper::VisitReturnStatement(ReturnStatement* stmt) { - // Collect type feedback. + RECURSE(Visit(stmt->expression())); + // TODO(rossberg): we only need this for inlining into test contexts... stmt->expression()->RecordToBooleanTypeFeedback(oracle()); - - RECURSE(Visit(stmt->expression())); - // TODO(rossberg): is it worth having a non-termination effect? } @@ -149,18 +133,14 @@ void AstTyper::VisitWithStatement(WithStatement* stmt) { void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) { RECURSE(Visit(stmt->tag())); - ZoneList<CaseClause*>* clauses = stmt->cases(); SwitchStatement::SwitchType switch_type = stmt->switch_type(); - Effects local_effects(zone()); - bool complex_effects = false; // True for label effects or fall-through. - for (int i = 0; i < clauses->length(); ++i) { CaseClause* clause = clauses->at(i); - Effects clause_effects = EnterEffects(); - if (!clause->is_default()) { Expression* label = clause->label(); + RECURSE(Visit(label)); + SwitchStatement::SwitchType label_switch_type = label->IsSmiLiteral() ? SwitchStatement::SMI_SWITCH : label->IsStringLiteral() ? SwitchStatement::STRING_SWITCH : @@ -169,32 +149,13 @@ void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) { switch_type = label_switch_type; else if (switch_type != label_switch_type) switch_type = SwitchStatement::GENERIC_SWITCH; - - RECURSE(Visit(label)); - if (!clause_effects.IsEmpty()) complex_effects = true; - } - - ZoneList<Statement*>* stmts = clause->statements(); - RECURSE(VisitStatements(stmts)); - ExitEffects(); - if (stmts->is_empty() || stmts->last()->IsJump()) { - local_effects.Alt(clause_effects); - } else { - complex_effects = true; } + RECURSE(VisitStatements(clause->statements())); } - - if (complex_effects) { - store_.Forget(); // Reached this in unknown state. - } else { - store_.Seq(local_effects); - } - if (switch_type == SwitchStatement::UNKNOWN_SWITCH) switch_type = SwitchStatement::GENERIC_SWITCH; stmt->set_switch_type(switch_type); - // Collect type feedback. // TODO(rossberg): can we eliminate this special case and extra loop? if (switch_type == SwitchStatement::SMI_SWITCH) { for (int i = 0; i < clauses->length(); ++i) { @@ -207,31 +168,22 @@ void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) { void AstTyper::VisitDoWhileStatement(DoWhileStatement* stmt) { - // Collect type feedback. + RECURSE(Visit(stmt->body())); + RECURSE(Visit(stmt->cond())); + if (!stmt->cond()->ToBooleanIsTrue()) { stmt->cond()->RecordToBooleanTypeFeedback(oracle()); } - - // TODO(rossberg): refine the unconditional Forget (here and elsewhere) by - // computing the set of variables assigned in only some of the origins of the - // control transfer (such as the loop body here). - store_.Forget(); // Control may transfer here via looping or 'continue'. - RECURSE(Visit(stmt->body())); - RECURSE(Visit(stmt->cond())); - store_.Forget(); // Control may transfer here via 'break'. } void AstTyper::VisitWhileStatement(WhileStatement* stmt) { - // Collect type feedback. + RECURSE(Visit(stmt->cond())); + RECURSE(Visit(stmt->body())); + if (!stmt->cond()->ToBooleanIsTrue()) { stmt->cond()->RecordToBooleanTypeFeedback(oracle()); } - - store_.Forget(); // Control may transfer here via looping or 'continue'. - RECURSE(Visit(stmt->cond())); - RECURSE(Visit(stmt->body())); - store_.Forget(); // Control may transfer here via termination or 'break'. } @@ -239,65 +191,45 @@ void AstTyper::VisitForStatement(ForStatement* stmt) { if (stmt->init() != NULL) { RECURSE(Visit(stmt->init())); } - store_.Forget(); // Control may transfer here via looping. if (stmt->cond() != NULL) { - // Collect type feedback. - stmt->cond()->RecordToBooleanTypeFeedback(oracle()); - RECURSE(Visit(stmt->cond())); + + stmt->cond()->RecordToBooleanTypeFeedback(oracle()); } RECURSE(Visit(stmt->body())); - store_.Forget(); // Control may transfer here via 'continue'. if (stmt->next() != NULL) { RECURSE(Visit(stmt->next())); } - store_.Forget(); // Control may transfer here via termination or 'break'. } void AstTyper::VisitForInStatement(ForInStatement* stmt) { - // Collect type feedback. - stmt->RecordTypeFeedback(oracle()); - RECURSE(Visit(stmt->enumerable())); - store_.Forget(); // Control may transfer here via looping or 'continue'. RECURSE(Visit(stmt->body())); - store_.Forget(); // Control may transfer here via 'break'. + + stmt->RecordTypeFeedback(oracle()); } void AstTyper::VisitForOfStatement(ForOfStatement* stmt) { RECURSE(Visit(stmt->iterable())); - store_.Forget(); // Control may transfer here via looping or 'continue'. RECURSE(Visit(stmt->body())); - store_.Forget(); // Control may transfer here via 'break'. } void AstTyper::VisitTryCatchStatement(TryCatchStatement* stmt) { - Effects try_effects = EnterEffects(); RECURSE(Visit(stmt->try_block())); - ExitEffects(); - Effects catch_effects = EnterEffects(); - store_.Forget(); // Control may transfer here via 'throw'. RECURSE(Visit(stmt->catch_block())); - ExitEffects(); - try_effects.Alt(catch_effects); - store_.Seq(try_effects); - // At this point, only variables that were reassigned in the catch block are - // still remembered. } void AstTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) { RECURSE(Visit(stmt->try_block())); - store_.Forget(); // Control may transfer here via 'throw'. RECURSE(Visit(stmt->finally_block())); } void AstTyper::VisitDebuggerStatement(DebuggerStatement* stmt) { - store_.Forget(); // May do whatever. } @@ -310,18 +242,11 @@ void AstTyper::VisitSharedFunctionInfoLiteral(SharedFunctionInfoLiteral* expr) { void AstTyper::VisitConditional(Conditional* expr) { - // Collect type feedback. - expr->condition()->RecordToBooleanTypeFeedback(oracle()); - RECURSE(Visit(expr->condition())); - Effects then_effects = EnterEffects(); RECURSE(Visit(expr->then_expression())); - ExitEffects(); - Effects else_effects = EnterEffects(); RECURSE(Visit(expr->else_expression())); - ExitEffects(); - then_effects.Alt(else_effects); - store_.Seq(then_effects); + + expr->condition()->RecordToBooleanTypeFeedback(oracle()); NarrowType(expr, Bounds::Either( expr->then_expression()->bounds(), @@ -330,10 +255,7 @@ void AstTyper::VisitConditional(Conditional* expr) { void AstTyper::VisitVariableProxy(VariableProxy* expr) { - Variable* var = expr->var(); - if (var->IsStackAllocated()) { - NarrowType(expr, store_.LookupBounds(variable_index(var))); - } + // TODO(rossberg): typing of variables } @@ -352,8 +274,8 @@ void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) { ZoneList<ObjectLiteral::Property*>* properties = expr->properties(); for (int i = 0; i < properties->length(); ++i) { ObjectLiteral::Property* prop = properties->at(i); + RECURSE(Visit(prop->value())); - // Collect type feedback. if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL && !CompileTimeValue::IsCompileTimeValue(prop->value())) || prop->kind() == ObjectLiteral::Property::COMPUTED) { @@ -361,8 +283,6 @@ void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) { prop->RecordTypeFeedback(oracle()); } } - - RECURSE(Visit(prop->value())); } NarrowType(expr, Bounds(Type::Object(), isolate_)); @@ -383,33 +303,29 @@ void AstTyper::VisitArrayLiteral(ArrayLiteral* expr) { void AstTyper::VisitAssignment(Assignment* expr) { // TODO(rossberg): Can we clean this up? if (expr->is_compound()) { - // Collect type feedback. + RECURSE(Visit(expr->binary_operation())); + Expression* target = expr->target(); Property* prop = target->AsProperty(); if (prop != NULL) { prop->RecordTypeFeedback(oracle(), zone()); - expr->RecordTypeFeedback(oracle(), zone()); + if (!prop->key()->IsPropertyName()) { // i.e., keyed + expr->RecordTypeFeedback(oracle(), zone()); + } } - RECURSE(Visit(expr->binary_operation())); - NarrowType(expr, expr->binary_operation()->bounds()); } else { - // Collect type feedback. - if (expr->target()->IsProperty()) { - expr->RecordTypeFeedback(oracle(), zone()); - } - RECURSE(Visit(expr->target())); RECURSE(Visit(expr->value())); - NarrowType(expr, expr->value()->bounds()); - } + if (expr->target()->AsProperty()) { + expr->RecordTypeFeedback(oracle(), zone()); + } - VariableProxy* proxy = expr->target()->AsVariableProxy(); - if (proxy != NULL && proxy->var()->IsStackAllocated()) { - store_.Seq(variable_index(proxy->var()), Effect(expr->bounds())); + NarrowType(expr, expr->value()->bounds()); } + // TODO(rossberg): handle target variables } @@ -417,40 +333,28 @@ void AstTyper::VisitYield(Yield* expr) { RECURSE(Visit(expr->generator_object())); RECURSE(Visit(expr->expression())); - // We don't know anything about the result type. + // We don't know anything about the type. } void AstTyper::VisitThrow(Throw* expr) { RECURSE(Visit(expr->exception())); - // TODO(rossberg): is it worth having a non-termination effect? NarrowType(expr, Bounds(Type::None(), isolate_)); } void AstTyper::VisitProperty(Property* expr) { - // Collect type feedback. - expr->RecordTypeFeedback(oracle(), zone()); - RECURSE(Visit(expr->obj())); RECURSE(Visit(expr->key())); - // We don't know anything about the result type. + expr->RecordTypeFeedback(oracle(), zone()); + + // We don't know anything about the type. } void AstTyper::VisitCall(Call* expr) { - // Collect type feedback. - Expression* callee = expr->expression(); - Property* prop = callee->AsProperty(); - if (prop != NULL) { - if (prop->key()->IsPropertyName()) - expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD); - } else { - expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION); - } - RECURSE(Visit(expr->expression())); ZoneList<Expression*>* args = expr->arguments(); for (int i = 0; i < args->length(); ++i) { @@ -458,19 +362,20 @@ void AstTyper::VisitCall(Call* expr) { RECURSE(Visit(arg)); } - VariableProxy* proxy = expr->expression()->AsVariableProxy(); - if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { - store_.Forget(); // Eval could do whatever to local variables. + Expression* callee = expr->expression(); + Property* prop = callee->AsProperty(); + if (prop != NULL) { + if (prop->key()->IsPropertyName()) + expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD); + } else { + expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION); } - // We don't know anything about the result type. + // We don't know anything about the type. } void AstTyper::VisitCallNew(CallNew* expr) { - // Collect type feedback. - expr->RecordTypeFeedback(oracle()); - RECURSE(Visit(expr->expression())); ZoneList<Expression*>* args = expr->arguments(); for (int i = 0; i < args->length(); ++i) { @@ -478,7 +383,9 @@ void AstTyper::VisitCallNew(CallNew* expr) { RECURSE(Visit(arg)); } - // We don't know anything about the result type. + expr->RecordTypeFeedback(oracle()); + + // We don't know anything about the type. } @@ -489,19 +396,21 @@ void AstTyper::VisitCallRuntime(CallRuntime* expr) { RECURSE(Visit(arg)); } - // We don't know anything about the result type. + // We don't know anything about the type. } void AstTyper::VisitUnaryOperation(UnaryOperation* expr) { + RECURSE(Visit(expr->expression())); + // Collect type feedback. + Handle<Type> op_type = oracle()->UnaryType(expr->UnaryOperationFeedbackId()); + NarrowLowerType(expr->expression(), op_type); if (expr->op() == Token::NOT) { // TODO(rossberg): only do in test or value context. expr->expression()->RecordToBooleanTypeFeedback(oracle()); } - RECURSE(Visit(expr->expression())); - switch (expr->op()) { case Token::NOT: case Token::DELETE: @@ -510,6 +419,16 @@ void AstTyper::VisitUnaryOperation(UnaryOperation* expr) { case Token::VOID: NarrowType(expr, Bounds(Type::Undefined(), isolate_)); break; + case Token::ADD: + case Token::SUB: { + Type* upper = *expr->expression()->bounds().upper; + if (!upper->Is(Type::Number())) upper = Type::Number(); + NarrowType(expr, Bounds(Type::Smi(), upper, isolate_)); + break; + } + case Token::BIT_NOT: + NarrowType(expr, Bounds(Type::Smi(), Type::Signed32(), isolate_)); + break; case Token::TYPEOF: NarrowType(expr, Bounds(Type::InternalizedString(), isolate_)); break; @@ -520,25 +439,22 @@ void AstTyper::VisitUnaryOperation(UnaryOperation* expr) { void AstTyper::VisitCountOperation(CountOperation* expr) { - // Collect type feedback. + RECURSE(Visit(expr->expression())); + expr->RecordTypeFeedback(oracle(), zone()); Property* prop = expr->expression()->AsProperty(); if (prop != NULL) { prop->RecordTypeFeedback(oracle(), zone()); } - RECURSE(Visit(expr->expression())); - NarrowType(expr, Bounds(Type::Smi(), Type::Number(), isolate_)); - - VariableProxy* proxy = expr->expression()->AsVariableProxy(); - if (proxy != NULL && proxy->var()->IsStackAllocated()) { - store_.Seq(variable_index(proxy->var()), Effect(expr->bounds())); - } } void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { + RECURSE(Visit(expr->left())); + RECURSE(Visit(expr->right())); + // Collect type feedback. Handle<Type> type, left_type, right_type; Maybe<int> fixed_right_arg; @@ -554,29 +470,15 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { switch (expr->op()) { case Token::COMMA: - RECURSE(Visit(expr->left())); - RECURSE(Visit(expr->right())); NarrowType(expr, expr->right()->bounds()); break; case Token::OR: - case Token::AND: { - Effects left_effects = EnterEffects(); - RECURSE(Visit(expr->left())); - ExitEffects(); - Effects right_effects = EnterEffects(); - RECURSE(Visit(expr->right())); - ExitEffects(); - left_effects.Alt(right_effects); - store_.Seq(left_effects); - + case Token::AND: NarrowType(expr, Bounds::Either( expr->left()->bounds(), expr->right()->bounds(), isolate_)); break; - } case Token::BIT_OR: case Token::BIT_AND: { - RECURSE(Visit(expr->left())); - RECURSE(Visit(expr->right())); Type* upper = Type::Union( expr->left()->bounds().upper, expr->right()->bounds().upper); if (!upper->Is(Type::Signed32())) upper = Type::Signed32(); @@ -586,18 +488,12 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { case Token::BIT_XOR: case Token::SHL: case Token::SAR: - RECURSE(Visit(expr->left())); - RECURSE(Visit(expr->right())); NarrowType(expr, Bounds(Type::Smi(), Type::Signed32(), isolate_)); break; case Token::SHR: - RECURSE(Visit(expr->left())); - RECURSE(Visit(expr->right())); NarrowType(expr, Bounds(Type::Smi(), Type::Unsigned32(), isolate_)); break; case Token::ADD: { - RECURSE(Visit(expr->left())); - RECURSE(Visit(expr->right())); Bounds l = expr->left()->bounds(); Bounds r = expr->right()->bounds(); Type* lower = @@ -617,8 +513,6 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { case Token::MUL: case Token::DIV: case Token::MOD: - RECURSE(Visit(expr->left())); - RECURSE(Visit(expr->right())); NarrowType(expr, Bounds(Type::Smi(), Type::Number(), isolate_)); break; default: @@ -628,6 +522,9 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { void AstTyper::VisitCompareOperation(CompareOperation* expr) { + RECURSE(Visit(expr->left())); + RECURSE(Visit(expr->right())); + // Collect type feedback. Handle<Type> left_type, right_type, combined_type; oracle()->CompareType(expr->CompareOperationFeedbackId(), @@ -636,9 +533,6 @@ void AstTyper::VisitCompareOperation(CompareOperation* expr) { NarrowLowerType(expr->right(), right_type); expr->set_combined_type(combined_type); - RECURSE(Visit(expr->left())); - RECURSE(Visit(expr->right())); - NarrowType(expr, Bounds(Type::Boolean(), isolate_)); } diff --git a/chromium/v8/src/typing.h b/chromium/v8/src/typing.h index c942b006327..ceef9843650 100644 --- a/chromium/v8/src/typing.h +++ b/chromium/v8/src/typing.h @@ -35,7 +35,6 @@ #include "compiler.h" #include "type-info.h" #include "types.h" -#include "effects.h" #include "zone.h" #include "scopes.h" @@ -58,13 +57,8 @@ class AstTyper: public AstVisitor { private: explicit AstTyper(CompilationInfo* info); - static const int kNoVar = INT_MIN; - typedef v8::internal::Effects<int, kNoVar> Effects; - typedef v8::internal::NestedEffects<int, kNoVar> Store; - CompilationInfo* info_; TypeFeedbackOracle oracle_; - Store store_; TypeFeedbackOracle* oracle() { return &oracle_; } Zone* zone() const { return info_->zone(); } @@ -76,17 +70,6 @@ class AstTyper: public AstVisitor { e->set_bounds(Bounds::NarrowLower(e->bounds(), t, isolate_)); } - Effects EnterEffects() { - store_ = store_.Push(); - return store_.Top(); - } - void ExitEffects() { store_ = store_.Pop(); } - - int variable_index(Variable* var) { - return var->IsStackLocal() ? var->index() : - var->IsParameter() ? -var->index() : kNoVar; - } - void VisitDeclarations(ZoneList<Declaration*>* declarations); void VisitStatements(ZoneList<Statement*>* statements); diff --git a/chromium/v8/src/v8.cc b/chromium/v8/src/v8.cc index 93f3efb2e3f..521d064129a 100644 --- a/chromium/v8/src/v8.cc +++ b/chromium/v8/src/v8.cc @@ -272,10 +272,9 @@ void V8::InitializeOncePerProcessImpl() { FLAG_max_new_space_size = (1 << (kPageSizeBits - 10)) * 2; } - if (FLAG_parallel_recompilation && - (FLAG_trace_hydrogen || FLAG_trace_hydrogen_stubs)) { + if (FLAG_trace_hydrogen || FLAG_trace_hydrogen_stubs) { + // Tracing hydrogen do not work with parallel recompilation. FLAG_parallel_recompilation = false; - PrintF("Parallel recompilation has been disabled for tracing.\n"); } if (FLAG_sweeper_threads <= 0) { diff --git a/chromium/v8/src/v8globals.h b/chromium/v8/src/v8globals.h index 6ec75478875..c3f1f01f944 100644 --- a/chromium/v8/src/v8globals.h +++ b/chromium/v8/src/v8globals.h @@ -363,8 +363,7 @@ enum StateTag { GC, COMPILER, OTHER, - EXTERNAL, - IDLE + EXTERNAL }; diff --git a/chromium/v8/src/version.cc b/chromium/v8/src/version.cc index 5142d389c21..292389aa4ab 100644 --- a/chromium/v8/src/version.cc +++ b/chromium/v8/src/version.cc @@ -34,8 +34,8 @@ // system so their names cannot be changed without changing the scripts. #define MAJOR_VERSION 3 #define MINOR_VERSION 20 -#define BUILD_NUMBER 17 -#define PATCH_LEVEL 0 +#define BUILD_NUMBER 15 +#define PATCH_LEVEL 5 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) #define IS_CANDIDATE_VERSION 0 diff --git a/chromium/v8/src/x64/assembler-x64-inl.h b/chromium/v8/src/x64/assembler-x64-inl.h index 826c06e5bad..ae9aeee8122 100644 --- a/chromium/v8/src/x64/assembler-x64-inl.h +++ b/chromium/v8/src/x64/assembler-x64-inl.h @@ -373,14 +373,13 @@ void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode mode) { bool RelocInfo::IsPatchedReturnSequence() { // The recognized call sequence is: - // movq(kScratchRegister, address); call(kScratchRegister); + // movq(kScratchRegister, immediate64); call(kScratchRegister); // It only needs to be distinguished from a return sequence // movq(rsp, rbp); pop(rbp); ret(n); int3 *6 // The 11th byte is int3 (0xCC) in the return sequence and // REX.WB (0x48+register bit) for the call sequence. #ifdef ENABLE_DEBUGGER_SUPPORT - return pc_[Assembler::kMoveAddressIntoScratchRegisterInstructionLength] != - 0xCC; + return pc_[2 + kPointerSize] != 0xCC; #else return false; #endif diff --git a/chromium/v8/src/x64/assembler-x64.cc b/chromium/v8/src/x64/assembler-x64.cc index 8969d89a6a7..f5939c3b7e1 100644 --- a/chromium/v8/src/x64/assembler-x64.cc +++ b/chromium/v8/src/x64/assembler-x64.cc @@ -164,7 +164,10 @@ void CpuFeatures::Probe() { // Patch the code at the current PC with a call to the target address. // Additional guard int3 instructions can be added if required. void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) { - int code_size = Assembler::kCallSequenceLength + guard_bytes; + // Load register with immediate 64 and call through a register instructions + // takes up 13 bytes and int3 takes up one byte. + static const int kCallCodeSize = 13; + int code_size = kCallCodeSize + guard_bytes; // Create a code patcher. CodePatcher patcher(pc_, code_size); @@ -180,7 +183,7 @@ void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) { patcher.masm()->call(r10); // Check that the size of the code generated is as expected. - ASSERT_EQ(Assembler::kCallSequenceLength, + ASSERT_EQ(kCallCodeSize, patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize)); // Add the requested number of int3 instructions after the call. diff --git a/chromium/v8/src/x64/assembler-x64.h b/chromium/v8/src/x64/assembler-x64.h index 4e36b6e4bc4..07afc129dc8 100644 --- a/chromium/v8/src/x64/assembler-x64.h +++ b/chromium/v8/src/x64/assembler-x64.h @@ -579,36 +579,29 @@ class Assembler : public AssemblerBase { // Distance between the address of the code target in the call instruction // and the return address pushed on the stack. static const int kCallTargetAddressOffset = 4; // Use 32-bit displacement. - // The length of call(kScratchRegister). - static const int kCallScratchRegisterInstructionLength = 3; - // The length of call(Immediate32). - static const int kShortCallInstructionLength = 5; - // The length of movq(kScratchRegister, address). - static const int kMoveAddressIntoScratchRegisterInstructionLength = - 2 + kPointerSize; - // The length of movq(kScratchRegister, address) and call(kScratchRegister). - static const int kCallSequenceLength = - kMoveAddressIntoScratchRegisterInstructionLength + - kCallScratchRegisterInstructionLength; - - // The js return and debug break slot must be able to contain an indirect - // call sequence, some x64 JS code is padded with int3 to make it large - // enough to hold an instruction when the debugger patches it. - static const int kJSReturnSequenceLength = kCallSequenceLength; - static const int kDebugBreakSlotLength = kCallSequenceLength; - static const int kPatchDebugBreakSlotReturnOffset = kCallTargetAddressOffset; - // Distance between the start of the JS return sequence and where the - // 32-bit displacement of a short call would be. The short call is from - // SetDebugBreakAtIC from debug-x64.cc. - static const int kPatchReturnSequenceAddressOffset = - kJSReturnSequenceLength - kPatchDebugBreakSlotReturnOffset; // Distance between the start of the JS return sequence and where the - // 32-bit displacement of a short call would be. The short call is from - // SetDebugBreakAtIC from debug-x64.cc. - static const int kPatchDebugBreakSlotAddressOffset = - kDebugBreakSlotLength - kPatchDebugBreakSlotReturnOffset; - static const int kRealPatchReturnSequenceAddressOffset = - kMoveAddressIntoScratchRegisterInstructionLength - kPointerSize; + // 32-bit displacement of a near call would be, relative to the pushed + // return address. TODO: Use return sequence length instead. + // Should equal Debug::kX64JSReturnSequenceLength - kCallTargetAddressOffset; + static const int kPatchReturnSequenceAddressOffset = 13 - 4; + // Distance between start of patched debug break slot and where the + // 32-bit displacement of a near call would be, relative to the pushed + // return address. TODO: Use return sequence length instead. + // Should equal Debug::kX64JSReturnSequenceLength - kCallTargetAddressOffset; + static const int kPatchDebugBreakSlotAddressOffset = 13 - 4; + // TODO(X64): Rename this, removing the "Real", after changing the above. + static const int kRealPatchReturnSequenceAddressOffset = 2; + + // Some x64 JS code is padded with int3 to make it large + // enough to hold an instruction when the debugger patches it. + static const int kJumpInstructionLength = 13; + static const int kCallInstructionLength = 13; + static const int kJSReturnSequenceLength = 13; + static const int kShortCallInstructionLength = 5; + static const int kPatchDebugBreakSlotReturnOffset = 4; + + // The debug break slot must be able to contain a call instruction. + static const int kDebugBreakSlotLength = kCallInstructionLength; // One byte opcode for test eax,0xXXXXXXXX. static const byte kTestEaxByte = 0xA9; diff --git a/chromium/v8/src/x64/builtins-x64.cc b/chromium/v8/src/x64/builtins-x64.cc index 18a6e566c6c..d34e4f70d9a 100644 --- a/chromium/v8/src/x64/builtins-x64.cc +++ b/chromium/v8/src/x64/builtins-x64.cc @@ -59,9 +59,9 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm, int num_extra_args = 0; if (extra_args == NEEDS_CALLED_FUNCTION) { num_extra_args = 1; - __ PopReturnAddressTo(kScratchRegister); + __ pop(kScratchRegister); // Save return address. __ push(rdi); - __ PushReturnAddressFrom(kScratchRegister); + __ push(kScratchRegister); // Restore return address. } else { ASSERT(extra_args == NO_EXTRA_ARGUMENTS); } @@ -249,7 +249,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, if (FLAG_debug_code) { __ cmpq(rsi, rdi); __ Assert(less_equal, - kUnexpectedNumberOfPreAllocatedPropertyFields); + "Unexpected number of pre-allocated property fields."); } __ InitializeFieldsWithFiller(rcx, rsi, rdx); __ LoadRoot(rdx, Heap::kOnePointerFillerMapRootIndex); @@ -280,7 +280,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, __ subq(rdx, rcx); // Done if no extra properties are to be allocated. __ j(zero, &allocated); - __ Assert(positive, kPropertyAllocationCountFailed); + __ Assert(positive, "Property allocation count failed."); // Scale the number of elements by pointer size and add the header for // FixedArrays to the start of the next object calculation from above. @@ -429,10 +429,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, } // Remove caller arguments from the stack and return. - __ PopReturnAddressTo(rcx); + __ pop(rcx); SmiIndex index = masm->SmiToIndex(rbx, rbx, kPointerSizeLog2); __ lea(rsp, Operand(rsp, index.reg, index.scale, 1 * kPointerSize)); - __ PushReturnAddressFrom(rcx); + __ push(rcx); Counters* counters = masm->isolate()->counters(); __ IncrementCounter(counters->constructed_objects(), 1); __ ret(0); @@ -723,7 +723,7 @@ static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm, __ ret(2 * kPointerSize); // Remove state, rax. __ bind(¬_tos_rax); - __ Abort(kNoCasesLeft); + __ Abort("no cases left"); } @@ -772,9 +772,9 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { { Label done; __ testq(rax, rax); __ j(not_zero, &done); - __ PopReturnAddressTo(rbx); + __ pop(rbx); __ Push(masm->isolate()->factory()->undefined_value()); - __ PushReturnAddressFrom(rbx); + __ push(rbx); __ incq(rax); __ bind(&done); } @@ -895,9 +895,9 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { __ cmpq(rdx, Immediate(1)); __ j(not_equal, &non_proxy); - __ PopReturnAddressTo(rdx); + __ pop(rdx); // return address __ push(rdi); // re-add proxy object as additional argument - __ PushReturnAddressFrom(rdx); + __ push(rdx); __ incq(rax); __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY); __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), @@ -1113,9 +1113,9 @@ void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { // Will both indicate a NULL and a Smi. STATIC_ASSERT(kSmiTag == 0); Condition not_smi = NegateCondition(masm->CheckSmi(rbx)); - __ Check(not_smi, kUnexpectedInitialMapForInternalArrayFunction); + __ Check(not_smi, "Unexpected initial map for InternalArray function"); __ CmpObjectType(rbx, MAP_TYPE, rcx); - __ Check(equal, kUnexpectedInitialMapForInternalArrayFunction); + __ Check(equal, "Unexpected initial map for InternalArray function"); } // Run the native code for the InternalArray function called as a normal @@ -1143,9 +1143,9 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { // Will both indicate a NULL and a Smi. STATIC_ASSERT(kSmiTag == 0); Condition not_smi = NegateCondition(masm->CheckSmi(rbx)); - __ Check(not_smi, kUnexpectedInitialMapForArrayFunction); + __ Check(not_smi, "Unexpected initial map for Array function"); __ CmpObjectType(rbx, MAP_TYPE, rcx); - __ Check(equal, kUnexpectedInitialMapForArrayFunction); + __ Check(equal, "Unexpected initial map for Array function"); } // Run the native code for the Array function called as a normal function. @@ -1173,7 +1173,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { if (FLAG_debug_code) { __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, rcx); __ cmpq(rdi, rcx); - __ Assert(equal, kUnexpectedStringFunction); + __ Assert(equal, "Unexpected String function"); } // Load the first argument into rax and get rid of the rest @@ -1182,9 +1182,9 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { __ testq(rax, rax); __ j(zero, &no_arguments); __ movq(rbx, Operand(rsp, rax, times_pointer_size, 0)); - __ PopReturnAddressTo(rcx); + __ pop(rcx); __ lea(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize)); - __ PushReturnAddressFrom(rcx); + __ push(rcx); __ movq(rax, rbx); // Lookup the argument in the number to string cache. @@ -1219,9 +1219,9 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { if (FLAG_debug_code) { __ cmpb(FieldOperand(rcx, Map::kInstanceSizeOffset), Immediate(JSValue::kSize >> kPointerSizeLog2)); - __ Assert(equal, kUnexpectedStringWrapperInstanceSize); + __ Assert(equal, "Unexpected string wrapper instance size"); __ cmpb(FieldOperand(rcx, Map::kUnusedPropertyFieldsOffset), Immediate(0)); - __ Assert(equal, kUnexpectedUnusedPropertiesOfStringWrapper); + __ Assert(equal, "Unexpected unused properties of string wrapper"); } __ movq(FieldOperand(rax, HeapObject::kMapOffset), rcx); @@ -1268,9 +1268,9 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { // stack, and jump back to the case where the argument is a string. __ bind(&no_arguments); __ LoadRoot(rbx, Heap::kempty_stringRootIndex); - __ PopReturnAddressTo(rcx); + __ pop(rcx); __ lea(rsp, Operand(rsp, kPointerSize)); - __ PushReturnAddressFrom(rcx); + __ push(rcx); __ jmp(&argument_is_string); // At this point the argument is already a string. Call runtime to @@ -1313,10 +1313,10 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { __ pop(rbp); // Remove caller arguments from the stack. - __ PopReturnAddressTo(rcx); + __ pop(rcx); SmiIndex index = masm->SmiToIndex(rbx, rbx, kPointerSizeLog2); __ lea(rsp, Operand(rsp, index.reg, index.scale, 1 * kPointerSize)); - __ PushReturnAddressFrom(rcx); + __ push(rcx); } diff --git a/chromium/v8/src/x64/code-stubs-x64.cc b/chromium/v8/src/x64/code-stubs-x64.cc index ad33a8c6319..551a71690e7 100644 --- a/chromium/v8/src/x64/code-stubs-x64.cc +++ b/chromium/v8/src/x64/code-stubs-x64.cc @@ -246,6 +246,17 @@ void ToBooleanStub::InitializeInterfaceDescriptor( } +void UnaryOpStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + static Register registers[] = { rax }; + descriptor->register_param_count_ = 1; + descriptor->register_params_ = registers; + descriptor->deoptimization_handler_ = + FUNCTION_ADDR(UnaryOpIC_Miss); +} + + void StoreGlobalStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { @@ -419,12 +430,12 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) { // Create a new closure through the slower runtime call. __ bind(&gc); - __ PopReturnAddressTo(rcx); + __ pop(rcx); // Temporarily remove return address. __ pop(rdx); __ push(rsi); __ push(rdx); __ PushRoot(Heap::kFalseValueRootIndex); - __ PushReturnAddressFrom(rcx); + __ push(rcx); // Restore return address. __ TailCallRuntime(Runtime::kNewClosure, 3, 1); } @@ -500,8 +511,9 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) { Label after_sentinel; __ JumpIfNotSmi(rcx, &after_sentinel, Label::kNear); if (FLAG_debug_code) { + const char* message = "Expected 0 as a Smi sentinel"; __ cmpq(rcx, Immediate(0)); - __ Assert(equal, kExpected0AsASmiSentinel); + __ Assert(equal, message); } __ movq(rcx, GlobalObjectOperand()); __ movq(rcx, FieldOperand(rcx, GlobalObject::kNativeContextOffset)); @@ -683,13 +695,13 @@ void BinaryOpStub::Initialize() {} void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { - __ PopReturnAddressTo(rcx); + __ pop(rcx); // Save return address. __ push(rdx); __ push(rax); // Left and right arguments are now on top. __ Push(Smi::FromInt(MinorKey())); - __ PushReturnAddressFrom(rcx); + __ push(rcx); // Push return address. // Patch the caller to an appropriate specialized stub and return the // operation result to the caller of the stub. @@ -942,7 +954,7 @@ static void BinaryOpStub_GenerateFloatingPointCode(MacroAssembler* masm, // Set the map. __ AssertRootValue(heap_number_map, Heap::kHeapNumberMapRootIndex, - kHeapNumberMapRegisterClobbered); + "HeapNumberMap register clobbered."); __ movq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map); __ cvtqsi2sd(xmm0, rbx); @@ -962,7 +974,8 @@ static void BinaryOpStub_GenerateFloatingPointCode(MacroAssembler* masm, } // No fall-through from this generated code. if (FLAG_debug_code) { - __ Abort(kUnexpectedFallThroughInBinaryStubGenerateFloatingPointCode); + __ Abort("Unexpected fall-through in " + "BinaryStub_GenerateFloatingPointCode."); } } @@ -971,10 +984,10 @@ static void BinaryOpStub_GenerateRegisterArgsPushUnderReturn( MacroAssembler* masm) { // Push arguments, but ensure they are under the return address // for a tail call. - __ PopReturnAddressTo(rcx); + __ pop(rcx); __ push(rdx); __ push(rax); - __ PushReturnAddressFrom(rcx); + __ push(rcx); } @@ -2142,10 +2155,10 @@ void StoreArrayLengthStub::Generate(MacroAssembler* masm) { __ JumpIfNotSmi(value, &miss); // Prepare tail call to StoreIC_ArrayLength. - __ PopReturnAddressTo(scratch); + __ pop(scratch); __ push(receiver); __ push(value); - __ PushReturnAddressFrom(scratch); + __ push(scratch); // return address ExternalReference ref = ExternalReference(IC_Utility(IC::kStoreIC_ArrayLength), masm->isolate()); @@ -2211,9 +2224,9 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { // Slow-case: Handle non-smi or out-of-bounds access to arguments // by calling the runtime system. __ bind(&slow); - __ PopReturnAddressTo(rbx); + __ pop(rbx); // Return address. __ push(rdx); - __ PushReturnAddressFrom(rbx); + __ push(rbx); __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); } @@ -2603,9 +2616,9 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { if (FLAG_debug_code) { Condition is_smi = masm->CheckSmi(rax); __ Check(NegateCondition(is_smi), - kUnexpectedTypeForRegExpDataFixedArrayExpected); + "Unexpected type for RegExp data, FixedArray expected"); __ CmpObjectType(rax, FIXED_ARRAY_TYPE, kScratchRegister); - __ Check(equal, kUnexpectedTypeForRegExpDataFixedArrayExpected); + __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); } // rax: RegExp data (FixedArray) @@ -2971,7 +2984,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // Assert that we do not have a cons or slice (indirect strings) here. // Sequential strings have already been ruled out. __ testb(rbx, Immediate(kIsIndirectStringMask)); - __ Assert(zero, kExternalStringExpectedButNotFound); + __ Assert(zero, "external string expected, but not found"); } __ movq(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset)); // Move the pointer so that offset-wise, it looks like a sequential string. @@ -3435,7 +3448,7 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { } #ifdef DEBUG - __ Abort(kUnexpectedFallThroughFromStringComparison); + __ Abort("Unexpected fall-through from string comparison"); #endif __ bind(&check_unequal_objects); @@ -3473,7 +3486,7 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { } // Push arguments below the return address to prepare jump to builtin. - __ PopReturnAddressTo(rcx); + __ pop(rcx); __ push(rdx); __ push(rax); @@ -3486,7 +3499,8 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { __ Push(Smi::FromInt(NegativeComparisonResult(cc))); } - __ PushReturnAddressFrom(rcx); + // Restore return address on the stack. + __ push(rcx); // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) // tagged as a small integer. @@ -3655,9 +3669,9 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { // Check for function proxy. __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE); __ j(not_equal, &non_function); - __ PopReturnAddressTo(rcx); + __ pop(rcx); __ push(rdi); // put proxy as additional argument under return address - __ PushReturnAddressFrom(rcx); + __ push(rcx); __ Set(rax, argc_ + 1); __ Set(rbx, 0); __ SetCallKind(rcx, CALL_AS_METHOD); @@ -4261,7 +4275,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) { if (FLAG_debug_code) { __ movl(rdi, Immediate(kWordBeforeMapCheckValue)); __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), rdi); - __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheCheck); + __ Assert(equal, "InstanceofStub unexpected call site cache (check)."); } __ movq(kScratchRegister, Operand(kScratchRegister, kOffsetToMapCheckValue)); @@ -4303,7 +4317,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) { if (FLAG_debug_code) { __ movl(rax, Immediate(kWordBeforeResultValue)); __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); - __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov); + __ Assert(equal, "InstanceofStub unexpected call site cache (mov)."); } __ Set(rax, 0); } @@ -4326,7 +4340,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) { if (FLAG_debug_code) { __ movl(rax, Immediate(kWordBeforeResultValue)); __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); - __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov); + __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); } } __ ret(2 * kPointerSize + extra_stack_space); @@ -4335,9 +4349,9 @@ void InstanceofStub::Generate(MacroAssembler* masm) { __ bind(&slow); if (HasCallSiteInlineCheck()) { // Remove extra value from the stack. - __ PopReturnAddressTo(rcx); + __ pop(rcx); __ pop(rax); - __ PushReturnAddressFrom(rcx); + __ push(rcx); } __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); } @@ -4390,7 +4404,7 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { void StringCharCodeAtGenerator::GenerateSlow( MacroAssembler* masm, const RuntimeCallHelper& call_helper) { - __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase); + __ Abort("Unexpected fallthrough to CharCodeAt slow case"); Factory* factory = masm->isolate()->factory(); // Index is not a smi. @@ -4440,7 +4454,7 @@ void StringCharCodeAtGenerator::GenerateSlow( call_helper.AfterCall(masm); __ jmp(&exit_); - __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase); + __ Abort("Unexpected fallthrough from CharCodeAt slow case"); } @@ -4466,7 +4480,7 @@ void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { void StringCharFromCodeGenerator::GenerateSlow( MacroAssembler* masm, const RuntimeCallHelper& call_helper) { - __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase); + __ Abort("Unexpected fallthrough to CharFromCode slow case"); __ bind(&slow_case_); call_helper.BeforeCall(masm); @@ -4478,7 +4492,7 @@ void StringCharFromCodeGenerator::GenerateSlow( call_helper.AfterCall(masm); __ jmp(&exit_); - __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); + __ Abort("Unexpected fallthrough from CharFromCode slow case"); } @@ -4808,10 +4822,10 @@ void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) { void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm, Register temp) { - __ PopReturnAddressTo(temp); + __ pop(temp); __ pop(rdx); __ pop(rax); - __ PushReturnAddressFrom(temp); + __ push(temp); } @@ -5026,7 +5040,7 @@ void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, if (FLAG_debug_code) { __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); __ cmpq(kScratchRegister, candidate); - __ Assert(equal, kOddballInStringTableIsNotUndefinedOrTheHole); + __ Assert(equal, "oddball in string table is not undefined or the hole"); } __ jmp(&next_probe[i]); @@ -5515,9 +5529,9 @@ void StringCompareStub::Generate(MacroAssembler* masm) { // Inline comparison of ASCII strings. __ IncrementCounter(counters->string_compare_native(), 1); // Drop arguments from the stack - __ PopReturnAddressTo(rcx); + __ pop(rcx); __ addq(rsp, Immediate(2 * kPointerSize)); - __ PushReturnAddressFrom(rcx); + __ push(rcx); GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8); // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) @@ -5786,10 +5800,10 @@ void ICCompareStub::GenerateStrings(MacroAssembler* masm) { // Handle more complex cases in runtime. __ bind(&runtime); - __ PopReturnAddressTo(tmp1); + __ pop(tmp1); // Return address. __ push(left); __ push(right); - __ PushReturnAddressFrom(tmp1); + __ push(tmp1); if (equality) { __ TailCallRuntime(Runtime::kStringEquals, 2, 1); } else { @@ -6397,14 +6411,16 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) { // the runtime. __ bind(&slow_elements); - __ PopReturnAddressTo(rdi); + __ pop(rdi); // Pop return address and remember to put back later for tail + // call. __ push(rbx); __ push(rcx); __ push(rax); __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); __ push(rdx); - __ PushReturnAddressFrom(rdi); + __ push(rdi); // Return return address so that tail call returns to right + // place. __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1); // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object. @@ -6451,7 +6467,7 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) { StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset; __ movq(rbx, MemOperand(rbp, parameter_count_offset)); masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE); - __ PopReturnAddressTo(rcx); + __ pop(rcx); int additional_offset = function_mode_ == JS_FUNCTION_STUB_MODE ? kPointerSize : 0; @@ -6523,7 +6539,7 @@ static void CreateArrayDispatch(MacroAssembler* masm) { } // If we reached this point there is a problem. - __ Abort(kUnexpectedElementsKindInArrayConstructor); + __ Abort("Unexpected ElementsKind in array constructor"); } @@ -6586,7 +6602,7 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm) { } // If we reached this point there is a problem. - __ Abort(kUnexpectedElementsKindInArrayConstructor); + __ Abort("Unexpected ElementsKind in array constructor"); } @@ -6652,9 +6668,9 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) { // Will both indicate a NULL and a Smi. STATIC_ASSERT(kSmiTag == 0); Condition not_smi = NegateCondition(masm->CheckSmi(rcx)); - __ Check(not_smi, kUnexpectedInitialMapForArrayFunction); + __ Check(not_smi, "Unexpected initial map for Array function"); __ CmpObjectType(rcx, MAP_TYPE, rcx); - __ Check(equal, kUnexpectedInitialMapForArrayFunction); + __ Check(equal, "Unexpected initial map for Array function"); // We should either have undefined in rbx or a valid cell Label okay_here; @@ -6662,7 +6678,7 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) { __ Cmp(rbx, undefined_sentinel); __ j(equal, &okay_here); __ Cmp(FieldOperand(rbx, 0), cell_map); - __ Assert(equal, kExpectedPropertyCellInRegisterRbx); + __ Assert(equal, "Expected property cell in register rbx"); __ bind(&okay_here); } @@ -6767,9 +6783,9 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { // Will both indicate a NULL and a Smi. STATIC_ASSERT(kSmiTag == 0); Condition not_smi = NegateCondition(masm->CheckSmi(rcx)); - __ Check(not_smi, kUnexpectedInitialMapForArrayFunction); + __ Check(not_smi, "Unexpected initial map for Array function"); __ CmpObjectType(rcx, MAP_TYPE, rcx); - __ Check(equal, kUnexpectedInitialMapForArrayFunction); + __ Check(equal, "Unexpected initial map for Array function"); } // Figure out the right elements kind @@ -6788,7 +6804,7 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { __ j(equal, &done); __ cmpl(rcx, Immediate(FAST_HOLEY_ELEMENTS)); __ Assert(equal, - kInvalidElementsKindForInternalArrayOrInternalPackedArray); + "Invalid ElementsKind for InternalArray or InternalPackedArray"); __ bind(&done); } diff --git a/chromium/v8/src/x64/codegen-x64.cc b/chromium/v8/src/x64/codegen-x64.cc index a39f14b0757..a823bf2e6d0 100644 --- a/chromium/v8/src/x64/codegen-x64.cc +++ b/chromium/v8/src/x64/codegen-x64.cc @@ -394,7 +394,7 @@ void ElementsTransitionGenerator::GenerateSmiToDouble( if (FLAG_debug_code) { __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); - __ Assert(equal, kObjectFoundInSmiOnlyArray); + __ Assert(equal, "object found in smi-only array"); } __ movq(FieldOperand(r14, r9, times_8, FixedDoubleArray::kHeaderSize), r15); @@ -577,7 +577,7 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm, // Assert that we do not have a cons or slice (indirect strings) here. // Sequential strings have already been ruled out. __ testb(result, Immediate(kIsIndirectStringMask)); - __ Assert(zero, kExternalStringExpectedButNotFound); + __ Assert(zero, "external string expected, but not found"); } // Rule out short external strings. STATIC_CHECK(kShortExternalStringTag != 0); diff --git a/chromium/v8/src/x64/debug-x64.cc b/chromium/v8/src/x64/debug-x64.cc index e6bc92950a9..a337b0d052f 100644 --- a/chromium/v8/src/x64/debug-x64.cc +++ b/chromium/v8/src/x64/debug-x64.cc @@ -48,10 +48,11 @@ bool BreakLocationIterator::IsDebugBreakAtReturn() { // CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x64.cc // for the precise return instructions sequence. void BreakLocationIterator::SetDebugBreakAtReturn() { - ASSERT(Assembler::kJSReturnSequenceLength >= Assembler::kCallSequenceLength); + ASSERT(Assembler::kJSReturnSequenceLength >= + Assembler::kCallInstructionLength); rinfo()->PatchCodeWithCall( Isolate::Current()->debug()->debug_break_return()->entry(), - Assembler::kJSReturnSequenceLength - Assembler::kCallSequenceLength); + Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength); } @@ -81,7 +82,7 @@ void BreakLocationIterator::SetDebugBreakAtSlot() { ASSERT(IsDebugBreakSlot()); rinfo()->PatchCodeWithCall( Isolate::Current()->debug()->debug_break_slot()->entry(), - Assembler::kDebugBreakSlotLength - Assembler::kCallSequenceLength); + Assembler::kDebugBreakSlotLength - Assembler::kCallInstructionLength); } diff --git a/chromium/v8/src/x64/deoptimizer-x64.cc b/chromium/v8/src/x64/deoptimizer-x64.cc index e9cf567f7e4..b45e9663e2a 100644 --- a/chromium/v8/src/x64/deoptimizer-x64.cc +++ b/chromium/v8/src/x64/deoptimizer-x64.cc @@ -42,7 +42,7 @@ const int Deoptimizer::table_entry_size_ = 10; int Deoptimizer::patch_size() { - return Assembler::kCallSequenceLength; + return Assembler::kCallInstructionLength; } @@ -69,7 +69,7 @@ void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) { Address call_address = instruction_start + deopt_data->Pc(i)->value(); // There is room enough to write a long call instruction because we pad // LLazyBailout instructions with nops if necessary. - CodePatcher patcher(call_address, Assembler::kCallSequenceLength); + CodePatcher patcher(call_address, Assembler::kCallInstructionLength); patcher.masm()->Call(GetDeoptimizationEntry(isolate, i, LAZY), RelocInfo::NONE64); ASSERT(prev_call_address == NULL || diff --git a/chromium/v8/src/x64/full-codegen-x64.cc b/chromium/v8/src/x64/full-codegen-x64.cc index 6333e87bea1..bac4e793b27 100644 --- a/chromium/v8/src/x64/full-codegen-x64.cc +++ b/chromium/v8/src/x64/full-codegen-x64.cc @@ -753,9 +753,9 @@ void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { // Check that we're not inside a with or catch context. __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset)); __ CompareRoot(rbx, Heap::kWithContextMapRootIndex); - __ Check(not_equal, kDeclarationInWithContext); + __ Check(not_equal, "Declaration in with context."); __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); - __ Check(not_equal, kDeclarationInCatchContext); + __ Check(not_equal, "Declaration in catch context."); } } @@ -2192,7 +2192,7 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator, __ Push(Smi::FromInt(resume_mode)); __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3); // Not reached: the runtime call returns elsewhere. - __ Abort(kGeneratorFailedToResume); + __ Abort("Generator failed to resume."); // Throw error if we attempt to operate on a running generator. __ bind(&wrong_state); @@ -2456,7 +2456,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, // Check for an uninitialized let binding. __ movq(rdx, location); __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); - __ Check(equal, kLetBindingReInitialization); + __ Check(equal, "Let binding re-initialization."); } // Perform the assignment. __ movq(location, rax); @@ -3398,14 +3398,14 @@ void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string, Register index, Register value, uint32_t encoding_mask) { - __ Check(masm()->CheckSmi(index), kNonSmiIndex); - __ Check(masm()->CheckSmi(value), kNonSmiValue); + __ Check(masm()->CheckSmi(index), "Non-smi index"); + __ Check(masm()->CheckSmi(value), "Non-smi value"); __ SmiCompare(index, FieldOperand(string, String::kLengthOffset)); - __ Check(less, kIndexIsTooLarge); + __ Check(less, "Index is too large"); __ SmiCompare(index, Smi::FromInt(0)); - __ Check(greater_equal, kIndexIsNegative); + __ Check(greater_equal, "Index is negative"); __ push(value); __ movq(value, FieldOperand(string, HeapObject::kMapOffset)); @@ -3413,7 +3413,7 @@ void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string, __ andb(value, Immediate(kStringRepresentationMask | kStringEncodingMask)); __ cmpq(value, Immediate(encoding_mask)); - __ Check(equal, kUnexpectedStringType); + __ Check(equal, "Unexpected string type"); __ pop(value); } @@ -3777,7 +3777,7 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { Handle<FixedArray> jsfunction_result_caches( isolate()->native_context()->jsfunction_result_caches()); if (jsfunction_result_caches->length() <= cache_id) { - __ Abort(kAttemptToUseUndefinedCache); + __ Abort("Attempt to use undefined cache."); __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); context()->Plug(rax); return; @@ -3971,7 +3971,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // scratch, string_length(int32), elements(FixedArray*). if (generate_debug_code_) { __ cmpq(index, array_length); - __ Assert(below, kNoEmptyArraysHereInEmitFastAsciiArrayJoin); + __ Assert(below, "No empty arrays here in EmitFastAsciiArrayJoin"); } __ bind(&loop); __ movq(string, FieldOperand(elements, @@ -4335,12 +4335,35 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { break; } + case Token::SUB: + EmitUnaryOperation(expr, "[ UnaryOperation (SUB)"); + break; + + case Token::BIT_NOT: + EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)"); + break; + default: UNREACHABLE(); } } +void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr, + const char* comment) { + // TODO(svenpanne): Allowing format strings in Comment would be nice here... + Comment cmt(masm_, comment); + UnaryOpStub stub(expr->op()); + // UnaryOpStub expects the argument to be in the + // accumulator register rax. + VisitForAccumulatorValue(expr->expression()); + SetSourcePosition(expr->position()); + CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, + expr->UnaryOperationFeedbackId()); + context()->Plug(rax); +} + + void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { Comment cmnt(masm_, "[ CountOperation"); SetSourcePosition(expr->position()); @@ -4796,7 +4819,7 @@ void FullCodeGenerator::EnterFinallyBlock() { ASSERT(!result_register().is(rdx)); ASSERT(!result_register().is(rcx)); // Cook return address on top of stack (smi encoded Code* delta) - __ PopReturnAddressTo(rdx); + __ pop(rdx); __ Move(rcx, masm_->CodeObject()); __ subq(rdx, rcx); __ Integer32ToSmi(rdx, rdx); diff --git a/chromium/v8/src/x64/ic-x64.cc b/chromium/v8/src/x64/ic-x64.cc index 4837b9aa9a8..6e238c76ece 100644 --- a/chromium/v8/src/x64/ic-x64.cc +++ b/chromium/v8/src/x64/ic-x64.cc @@ -570,10 +570,10 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { __ j(not_zero, &slow); // Everything is fine, call runtime. - __ PopReturnAddressTo(rcx); + __ pop(rcx); __ push(rdx); // receiver __ push(rax); // key - __ PushReturnAddressFrom(rcx); + __ push(rcx); // return address // Perform tail call to the entry. __ TailCallExternalReference( @@ -1369,10 +1369,10 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) { Counters* counters = masm->isolate()->counters(); __ IncrementCounter(counters->load_miss(), 1); - __ PopReturnAddressTo(rbx); + __ pop(rbx); __ push(rax); // receiver __ push(rcx); // name - __ PushReturnAddressFrom(rbx); + __ push(rbx); // return address // Perform tail call to the entry. ExternalReference ref = @@ -1388,10 +1388,10 @@ void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { // -- rsp[0] : return address // ----------------------------------- - __ PopReturnAddressTo(rbx); + __ pop(rbx); __ push(rax); // receiver __ push(rcx); // name - __ PushReturnAddressFrom(rbx); + __ push(rbx); // return address // Perform tail call to the entry. __ TailCallRuntime(Runtime::kGetProperty, 2, 1); @@ -1408,10 +1408,10 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) { Counters* counters = masm->isolate()->counters(); __ IncrementCounter(counters->keyed_load_miss(), 1); - __ PopReturnAddressTo(rbx); + __ pop(rbx); __ push(rdx); // receiver __ push(rax); // name - __ PushReturnAddressFrom(rbx); + __ push(rbx); // return address // Perform tail call to the entry. ExternalReference ref = miss_mode == MISS_FORCE_GENERIC @@ -1429,10 +1429,10 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { // -- rsp[0] : return address // ----------------------------------- - __ PopReturnAddressTo(rbx); + __ pop(rbx); __ push(rdx); // receiver __ push(rax); // name - __ PushReturnAddressFrom(rbx); + __ push(rbx); // return address // Perform tail call to the entry. __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); @@ -1468,11 +1468,11 @@ void StoreIC::GenerateMiss(MacroAssembler* masm) { // -- rsp[0] : return address // ----------------------------------- - __ PopReturnAddressTo(rbx); + __ pop(rbx); __ push(rdx); // receiver __ push(rcx); // name __ push(rax); // value - __ PushReturnAddressFrom(rbx); + __ push(rbx); // return address // Perform tail call to the entry. ExternalReference ref = @@ -1512,13 +1512,13 @@ void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, // -- rdx : receiver // -- rsp[0] : return address // ----------------------------------- - __ PopReturnAddressTo(rbx); + __ pop(rbx); __ push(rdx); __ push(rcx); __ push(rax); __ Push(Smi::FromInt(NONE)); // PropertyAttributes __ Push(Smi::FromInt(strict_mode)); - __ PushReturnAddressFrom(rbx); + __ push(rbx); // return address // Do tail-call to runtime routine. __ TailCallRuntime(Runtime::kSetProperty, 5, 1); @@ -1534,13 +1534,13 @@ void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, // -- rsp[0] : return address // ----------------------------------- - __ PopReturnAddressTo(rbx); + __ pop(rbx); __ push(rdx); // receiver __ push(rcx); // key __ push(rax); // value __ Push(Smi::FromInt(NONE)); // PropertyAttributes __ Push(Smi::FromInt(strict_mode)); // Strict mode. - __ PushReturnAddressFrom(rbx); + __ push(rbx); // return address // Do tail-call to runtime routine. __ TailCallRuntime(Runtime::kSetProperty, 5, 1); @@ -1555,11 +1555,11 @@ void StoreIC::GenerateSlow(MacroAssembler* masm) { // -- rsp[0] : return address // ----------------------------------- - __ PopReturnAddressTo(rbx); + __ pop(rbx); __ push(rdx); // receiver __ push(rcx); // key __ push(rax); // value - __ PushReturnAddressFrom(rbx); + __ push(rbx); // return address // Do tail-call to runtime routine. ExternalReference ref(IC_Utility(kStoreIC_Slow), masm->isolate()); @@ -1575,11 +1575,11 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { // -- rsp[0] : return address // ----------------------------------- - __ PopReturnAddressTo(rbx); + __ pop(rbx); __ push(rdx); // receiver __ push(rcx); // key __ push(rax); // value - __ PushReturnAddressFrom(rbx); + __ push(rbx); // return address // Do tail-call to runtime routine. ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate()); @@ -1595,11 +1595,11 @@ void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) { // -- rsp[0] : return address // ----------------------------------- - __ PopReturnAddressTo(rbx); + __ pop(rbx); __ push(rdx); // receiver __ push(rcx); // key __ push(rax); // value - __ PushReturnAddressFrom(rbx); + __ push(rbx); // return address // Do tail-call to runtime routine. ExternalReference ref = miss_mode == MISS_FORCE_GENERIC diff --git a/chromium/v8/src/x64/lithium-codegen-x64.cc b/chromium/v8/src/x64/lithium-codegen-x64.cc index abb8c77b5b7..c2207317c18 100644 --- a/chromium/v8/src/x64/lithium-codegen-x64.cc +++ b/chromium/v8/src/x64/lithium-codegen-x64.cc @@ -96,7 +96,7 @@ void LCodeGen::FinishCode(Handle<Code> code) { } -void LChunkBuilder::Abort(BailoutReason reason) { +void LChunkBuilder::Abort(const char* reason) { info()->set_bailout_reason(reason); status_ = ABORTED; } @@ -278,8 +278,6 @@ bool LCodeGen::GenerateBody() { instr->Mnemonic()); } - RecordAndUpdatePosition(instr->position()); - instr->CompileToNative(this); } EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); @@ -333,10 +331,6 @@ bool LCodeGen::GenerateDeferredCode() { if (deferred_.length() > 0) { for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { LDeferredCode* code = deferred_[i]; - - int pos = instructions_->at(code->instruction_index())->position(); - RecordAndUpdatePosition(pos); - Comment(";;; <@%d,#%d> " "-------------------- Deferred %s --------------------", code->instruction_index(), @@ -503,57 +497,37 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, break; } - int object_index = 0; - int dematerialized_index = 0; for (int i = 0; i < translation_size; ++i) { LOperand* value = environment->values()->at(i); - AddToTranslation(environment, - translation, + + // TODO(mstarzinger): Introduce marker operands to indicate that this value + // is not present and must be reconstructed from the deoptimizer. Currently + // this is only used for the arguments object. + if (value == NULL) { + int arguments_count = environment->values()->length() - translation_size; + translation->BeginArgumentsObject(arguments_count); + for (int i = 0; i < arguments_count; ++i) { + LOperand* value = environment->values()->at(translation_size + i); + AddToTranslation(translation, + value, + environment->HasTaggedValueAt(translation_size + i), + environment->HasUint32ValueAt(translation_size + i)); + } + continue; + } + + AddToTranslation(translation, value, environment->HasTaggedValueAt(i), - environment->HasUint32ValueAt(i), - &object_index, - &dematerialized_index); + environment->HasUint32ValueAt(i)); } } -void LCodeGen::AddToTranslation(LEnvironment* environment, - Translation* translation, +void LCodeGen::AddToTranslation(Translation* translation, LOperand* op, bool is_tagged, - bool is_uint32, - int* object_index_pointer, - int* dematerialized_index_pointer) { - if (op == LEnvironment::materialization_marker()) { - int object_index = (*object_index_pointer)++; - if (environment->ObjectIsDuplicateAt(object_index)) { - int dupe_of = environment->ObjectDuplicateOfAt(object_index); - translation->DuplicateObject(dupe_of); - return; - } - int object_length = environment->ObjectLengthAt(object_index); - if (environment->ObjectIsArgumentsAt(object_index)) { - translation->BeginArgumentsObject(object_length); - } else { - translation->BeginCapturedObject(object_length); - } - int dematerialized_index = *dematerialized_index_pointer; - int env_offset = environment->translation_size() + dematerialized_index; - *dematerialized_index_pointer += object_length; - for (int i = 0; i < object_length; ++i) { - LOperand* value = environment->values()->at(env_offset + i); - AddToTranslation(environment, - translation, - value, - environment->HasTaggedValueAt(env_offset + i), - environment->HasUint32ValueAt(env_offset + i), - object_index_pointer, - dematerialized_index_pointer); - } - return; - } - + bool is_uint32) { if (op->IsStackSlot()) { if (is_tagged) { translation->StoreStackSlot(op->index()); @@ -687,13 +661,13 @@ void LCodeGen::DeoptimizeIf(Condition cc, Address entry = Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type); if (entry == NULL) { - Abort(kBailoutWasNotPrepared); + Abort("bailout was not prepared"); return; } ASSERT(FLAG_deopt_every_n_times == 0); // Not yet implemented on x64. - if (info()->ShouldTrapOnDeopt()) { + if (FLAG_trap_on_deopt && info()->IsOptimizing()) { Label done; if (cc != no_condition) { __ j(NegateCondition(cc), &done, Label::kNear); @@ -885,14 +859,6 @@ void LCodeGen::RecordPosition(int position) { } -void LCodeGen::RecordAndUpdatePosition(int position) { - if (position >= 0 && position != old_position_) { - masm()->positions_recorder()->RecordPosition(position); - old_position_ = position; - } -} - - static const char* LabelType(LLabel* label) { if (label->is_loop_header()) return " (loop header)"; if (label->is_osr_entry()) return " (OSR entry)"; @@ -1304,7 +1270,7 @@ void LCodeGen::DoMulI(LMulI* instr) { bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); if (right->IsConstantOperand()) { - int32_t right_value = ToInteger32(LConstantOperand::cast(right)); + int right_value = ToInteger32(LConstantOperand::cast(right)); if (right_value == -1) { __ negl(left); } else if (right_value == 0) { @@ -1396,7 +1362,7 @@ void LCodeGen::DoBitI(LBitI* instr) { ASSERT(left->IsRegister()); if (right->IsConstantOperand()) { - int32_t right_operand = ToInteger32(LConstantOperand::cast(right)); + int right_operand = ToInteger32(LConstantOperand::cast(right)); switch (instr->op()) { case Token::BIT_AND: __ andl(ToRegister(left), Immediate(right_operand)); @@ -1405,11 +1371,7 @@ void LCodeGen::DoBitI(LBitI* instr) { __ orl(ToRegister(left), Immediate(right_operand)); break; case Token::BIT_XOR: - if (right_operand == int32_t(~0)) { - __ not_(ToRegister(left)); - } else { - __ xorl(ToRegister(left), Immediate(right_operand)); - } + __ xorl(ToRegister(left), Immediate(right_operand)); break; default: UNREACHABLE(); @@ -1480,7 +1442,7 @@ void LCodeGen::DoShiftI(LShiftI* instr) { break; } } else { - int32_t value = ToInteger32(LConstantOperand::cast(right)); + int value = ToInteger32(LConstantOperand::cast(right)); uint8_t shift_count = static_cast<uint8_t>(value & 0x1F); switch (instr->op()) { case Token::ROR: @@ -1680,7 +1642,7 @@ void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; __ cmpq(value, Immediate(encoding == String::ONE_BYTE_ENCODING ? one_byte_seq_type : two_byte_seq_type)); - __ Check(equal, kUnexpectedStringType); + __ Check(equal, "Unexpected string type"); __ pop(value); } @@ -1694,6 +1656,13 @@ void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { } +void LCodeGen::DoBitNotI(LBitNotI* instr) { + LOperand* input = instr->value(); + ASSERT(input->Equals(instr->result())); + __ not_(ToRegister(input)); +} + + void LCodeGen::DoThrow(LThrow* instr) { __ push(ToRegister(instr->value())); CallRuntime(Runtime::kThrow, 1, instr); @@ -1900,13 +1869,6 @@ void LCodeGen::EmitBranch(InstrType instr, Condition cc) { } -template<class InstrType> -void LCodeGen::EmitFalseBranch(InstrType instr, Condition cc) { - int false_block = instr->FalseDestination(chunk_); - __ j(cc, chunk_->GetAssemblyLabel(false_block)); -} - - void LCodeGen::DoDebugBreak(LDebugBreak* instr) { __ int3(); } @@ -2180,28 +2142,6 @@ void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { } -void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) { - if (instr->hydrogen()->representation().IsTagged()) { - Register input_reg = ToRegister(instr->object()); - __ Cmp(input_reg, factory()->the_hole_value()); - EmitBranch(instr, equal); - return; - } - - XMMRegister input_reg = ToDoubleRegister(instr->object()); - __ ucomisd(input_reg, input_reg); - EmitFalseBranch(instr, parity_odd); - - __ subq(rsp, Immediate(kDoubleSize)); - __ movsd(MemOperand(rsp, 0), input_reg); - __ addq(rsp, Immediate(kDoubleSize)); - - int offset = sizeof(kHoleNanUpper32); - __ cmpl(MemOperand(rsp, -offset), Immediate(kHoleNanUpper32)); - EmitBranch(instr, equal); -} - - Condition LCodeGen::EmitIsObject(Register input, Label* is_not_object, Label* is_object) { @@ -2634,7 +2574,7 @@ void LCodeGen::DoReturn(LReturn* instr) { // The argument count parameter is a smi __ SmiToInteger32(reg, reg); Register return_addr_reg = reg.is(rcx) ? rbx : rcx; - __ PopReturnAddressTo(return_addr_reg); + __ pop(return_addr_reg); __ shl(reg, Immediate(kPointerSizeLog2)); __ addq(rsp, reg); __ jmp(return_addr_reg); @@ -2793,6 +2733,111 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { } +void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, + Register object, + Handle<Map> type, + Handle<String> name, + LEnvironment* env) { + LookupResult lookup(isolate()); + type->LookupDescriptor(NULL, *name, &lookup); + ASSERT(lookup.IsFound() || lookup.IsCacheable()); + if (lookup.IsField()) { + int index = lookup.GetLocalFieldIndexFromMap(*type); + int offset = index * kPointerSize; + if (index < 0) { + // Negative property indices are in-object properties, indexed + // from the end of the fixed part of the object. + __ movq(result, FieldOperand(object, offset + type->instance_size())); + } else { + // Non-negative property indices are in the properties array. + __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset)); + __ movq(result, FieldOperand(result, offset + FixedArray::kHeaderSize)); + } + } else if (lookup.IsConstant()) { + Handle<Object> constant(lookup.GetConstantFromMap(*type), isolate()); + __ LoadObject(result, constant); + } else { + // Negative lookup. + // Check prototypes. + Handle<HeapObject> current(HeapObject::cast((*type)->prototype())); + Heap* heap = type->GetHeap(); + while (*current != heap->null_value()) { + __ LoadHeapObject(result, current); + __ Cmp(FieldOperand(result, HeapObject::kMapOffset), + Handle<Map>(current->map())); + DeoptimizeIf(not_equal, env); + current = + Handle<HeapObject>(HeapObject::cast(current->map()->prototype())); + } + __ LoadRoot(result, Heap::kUndefinedValueRootIndex); + } +} + + +// Check for cases where EmitLoadFieldOrConstantFunction needs to walk the +// prototype chain, which causes unbounded code generation. +static bool CompactEmit(SmallMapList* list, + Handle<String> name, + int i, + Isolate* isolate) { + Handle<Map> map = list->at(i); + LookupResult lookup(isolate); + map->LookupDescriptor(NULL, *name, &lookup); + return lookup.IsField() || lookup.IsConstant(); +} + + +void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) { + Register object = ToRegister(instr->object()); + Register result = ToRegister(instr->result()); + + int map_count = instr->hydrogen()->types()->length(); + bool need_generic = instr->hydrogen()->need_generic(); + + if (map_count == 0 && !need_generic) { + DeoptimizeIf(no_condition, instr->environment()); + return; + } + Handle<String> name = instr->hydrogen()->name(); + Label done; + bool all_are_compact = true; + for (int i = 0; i < map_count; ++i) { + if (!CompactEmit(instr->hydrogen()->types(), name, i, isolate())) { + all_are_compact = false; + break; + } + } + for (int i = 0; i < map_count; ++i) { + bool last = (i == map_count - 1); + Handle<Map> map = instr->hydrogen()->types()->at(i); + Label check_passed; + __ CompareMap(object, map, &check_passed); + if (last && !need_generic) { + DeoptimizeIf(not_equal, instr->environment()); + __ bind(&check_passed); + EmitLoadFieldOrConstantFunction( + result, object, map, name, instr->environment()); + } else { + Label next; + bool compact = all_are_compact ? true : + CompactEmit(instr->hydrogen()->types(), name, i, isolate()); + __ j(not_equal, &next, compact ? Label::kNear : Label::kFar); + __ bind(&check_passed); + EmitLoadFieldOrConstantFunction( + result, object, map, name, instr->environment()); + __ jmp(&done, all_are_compact ? Label::kNear : Label::kFar); + __ bind(&next); + } + } + if (need_generic) { + __ Move(rcx, name); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); + CallCode(ic, RelocInfo::CODE_TARGET, instr); + } + __ bind(&done); +} + + void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { ASSERT(ToRegister(instr->object()).is(rax)); ASSERT(ToRegister(instr->result()).is(rax)); @@ -2859,8 +2904,8 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { if (instr->length()->IsConstantOperand() && instr->index()->IsConstantOperand()) { - int32_t const_index = ToInteger32(LConstantOperand::cast(instr->index())); - int32_t const_length = ToInteger32(LConstantOperand::cast(instr->length())); + int const_index = ToInteger32(LConstantOperand::cast(instr->index())); + int const_length = ToInteger32(LConstantOperand::cast(instr->length())); int index = (const_length - const_index) + 1; __ movq(result, Operand(arguments, index * kPointerSize)); } else { @@ -3047,9 +3092,9 @@ Operand LCodeGen::BuildFastArrayOperand( Register elements_pointer_reg = ToRegister(elements_pointer); int shift_size = ElementsKindToShiftSize(elements_kind); if (key->IsConstantOperand()) { - int32_t constant_value = ToInteger32(LConstantOperand::cast(key)); + int constant_value = ToInteger32(LConstantOperand::cast(key)); if (constant_value & 0xF0000000) { - Abort(kArrayIndexConstantValueTooBig); + Abort("array index constant value too big"); } return Operand(elements_pointer_reg, ((constant_value + additional_index) << shift_size) @@ -3387,17 +3432,6 @@ void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) { } -void LCodeGen::EmitSmiMathAbs(LMathAbs* instr) { - Register input_reg = ToRegister(instr->value()); - __ testq(input_reg, input_reg); - Label is_positive; - __ j(not_sign, &is_positive, Label::kNear); - __ neg(input_reg); // Sets flags. - DeoptimizeIf(negative, instr->environment()); - __ bind(&is_positive); -} - - void LCodeGen::DoMathAbs(LMathAbs* instr) { // Class for deferred case. class DeferredMathAbsTaggedHeapNumber: public LDeferredCode { @@ -3423,15 +3457,15 @@ void LCodeGen::DoMathAbs(LMathAbs* instr) { __ andpd(input_reg, scratch); } else if (r.IsInteger32()) { EmitIntegerMathAbs(instr); - } else if (r.IsSmi()) { - EmitSmiMathAbs(instr); } else { // Tagged case. DeferredMathAbsTaggedHeapNumber* deferred = new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr); Register input_reg = ToRegister(instr->value()); // Smi check. __ JumpIfNotSmi(input_reg, deferred->entry()); - EmitSmiMathAbs(instr); + __ SmiToInteger32(input_reg, input_reg); + EmitIntegerMathAbs(instr); + __ Integer32ToSmi(input_reg, input_reg); __ bind(deferred->exit()); } } @@ -4055,7 +4089,7 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { __ AssertZeroExtended(reg); } if (instr->index()->IsConstantOperand()) { - int32_t constant_index = + int constant_index = ToInteger32(LConstantOperand::cast(instr->index())); if (instr->hydrogen()->length()->representation().IsSmi()) { __ Cmp(reg, Smi::FromInt(constant_index)); @@ -4072,7 +4106,7 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { } else { Operand length = ToOperand(instr->length()); if (instr->index()->IsConstantOperand()) { - int32_t constant_index = + int constant_index = ToInteger32(LConstantOperand::cast(instr->index())); if (instr->hydrogen()->length()->representation().IsSmi()) { __ Cmp(length, Smi::FromInt(constant_index)); @@ -4359,7 +4393,7 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { // DoStringCharCodeAt above. STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); if (instr->index()->IsConstantOperand()) { - int32_t const_index = ToInteger32(LConstantOperand::cast(instr->index())); + int const_index = ToInteger32(LConstantOperand::cast(instr->index())); __ Push(Smi::FromInt(const_index)); } else { Register index = ToRegister(instr->index()); @@ -4545,6 +4579,36 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { Register reg = ToRegister(instr->result()); Register tmp = ToRegister(instr->temp()); + bool convert_hole = false; + HValue* change_input = instr->hydrogen()->value(); + if (change_input->IsLoadKeyed()) { + HLoadKeyed* load = HLoadKeyed::cast(change_input); + convert_hole = load->UsesMustHandleHole(); + } + + Label no_special_nan_handling; + Label done; + if (convert_hole) { + XMMRegister input_reg = ToDoubleRegister(instr->value()); + __ ucomisd(input_reg, input_reg); + __ j(parity_odd, &no_special_nan_handling); + __ subq(rsp, Immediate(kDoubleSize)); + __ movsd(MemOperand(rsp, 0), input_reg); + __ cmpl(MemOperand(rsp, sizeof(kHoleNanLower32)), + Immediate(kHoleNanUpper32)); + Label canonicalize; + __ j(not_equal, &canonicalize); + __ addq(rsp, Immediate(kDoubleSize)); + __ Move(reg, factory()->the_hole_value()); + __ jmp(&done); + __ bind(&canonicalize); + __ addq(rsp, Immediate(kDoubleSize)); + __ Set(kScratchRegister, BitCast<uint64_t>( + FixedDoubleArray::canonical_not_the_hole_nan_as_double())); + __ movq(input_reg, kScratchRegister); + } + + __ bind(&no_special_nan_handling); DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr); if (FLAG_inline_new) { __ AllocateHeapNumber(reg, tmp, deferred->entry()); @@ -4553,6 +4617,8 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { } __ bind(deferred->exit()); __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), input_reg); + + __ bind(&done); } @@ -4596,20 +4662,22 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { void LCodeGen::EmitNumberUntagD(Register input_reg, XMMRegister result_reg, - bool can_convert_undefined_to_nan, + bool allow_undefined_as_nan, bool deoptimize_on_minus_zero, LEnvironment* env, NumberUntagDMode mode) { Label load_smi, done; - if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) { + STATIC_ASSERT(NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE > + NUMBER_CANDIDATE_IS_ANY_TAGGED); + if (mode >= NUMBER_CANDIDATE_IS_ANY_TAGGED) { // Smi check. __ JumpIfSmi(input_reg, &load_smi, Label::kNear); // Heap number map check. __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), Heap::kHeapNumberMapRootIndex); - if (!can_convert_undefined_to_nan) { + if (!allow_undefined_as_nan) { DeoptimizeIf(not_equal, env); } else { Label heap_number, convert; @@ -4617,6 +4685,10 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, // Convert undefined (and hole) to NaN. Compute NaN as 0/0. __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex); + if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE) { + __ j(equal, &convert, Label::kNear); + __ CompareRoot(input_reg, Heap::kTheHoleValueRootIndex); + } DeoptimizeIf(not_equal, env); __ bind(&convert); @@ -4729,12 +4801,19 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { Register input_reg = ToRegister(input); XMMRegister result_reg = ToDoubleRegister(result); + NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED; HValue* value = instr->hydrogen()->value(); - NumberUntagDMode mode = value->representation().IsSmi() - ? NUMBER_CANDIDATE_IS_SMI : NUMBER_CANDIDATE_IS_ANY_TAGGED; + if (value->type().IsSmi()) { + mode = NUMBER_CANDIDATE_IS_SMI; + } else if (value->IsLoadKeyed()) { + HLoadKeyed* load = HLoadKeyed::cast(value); + if (load->UsesMustHandleHole()) { + mode = NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE; + } + } EmitNumberUntagD(input_reg, result_reg, - instr->hydrogen()->can_convert_undefined_to_nan(), + instr->hydrogen()->allow_undefined_as_nan(), instr->hydrogen()->deoptimize_on_minus_zero(), instr->environment(), mode); @@ -4888,64 +4967,31 @@ void LCodeGen::DoCheckFunction(LCheckFunction* instr) { } -void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) { - { - PushSafepointRegistersScope scope(this); - __ push(object); - CallRuntimeFromDeferred(Runtime::kMigrateInstance, 1, instr); - __ testq(rax, Immediate(kSmiTagMask)); - } - DeoptimizeIf(zero, instr->environment()); +void LCodeGen::DoCheckMapCommon(Register reg, + Handle<Map> map, + LInstruction* instr) { + Label success; + __ CompareMap(reg, map, &success); + DeoptimizeIf(not_equal, instr->environment()); + __ bind(&success); } void LCodeGen::DoCheckMaps(LCheckMaps* instr) { - class DeferredCheckMaps: public LDeferredCode { - public: - DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object) - : LDeferredCode(codegen), instr_(instr), object_(object) { - SetExit(check_maps()); - } - virtual void Generate() { - codegen()->DoDeferredInstanceMigration(instr_, object_); - } - Label* check_maps() { return &check_maps_; } - virtual LInstruction* instr() { return instr_; } - private: - LCheckMaps* instr_; - Label check_maps_; - Register object_; - }; - if (instr->hydrogen()->CanOmitMapChecks()) return; - LOperand* input = instr->value(); ASSERT(input->IsRegister()); Register reg = ToRegister(input); - SmallMapList* map_set = instr->hydrogen()->map_set(); - - DeferredCheckMaps* deferred = NULL; - if (instr->hydrogen()->has_migration_target()) { - deferred = new(zone()) DeferredCheckMaps(this, instr, reg); - __ bind(deferred->check_maps()); - } - Label success; + SmallMapList* map_set = instr->hydrogen()->map_set(); for (int i = 0; i < map_set->length() - 1; i++) { Handle<Map> map = map_set->at(i); __ CompareMap(reg, map, &success); __ j(equal, &success); } - Handle<Map> map = map_set->last(); - __ CompareMap(reg, map, &success); - if (instr->hydrogen()->has_migration_target()) { - __ j(not_equal, deferred->entry()); - } else { - DeoptimizeIf(not_equal, instr->environment()); - } - + DoCheckMapCommon(reg, map, instr); __ bind(&success); } @@ -4999,6 +5045,22 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { } +void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { + if (instr->hydrogen()->CanOmitPrototypeChecks()) return; + Register reg = ToRegister(instr->temp()); + + ZoneList<Handle<JSObject> >* prototypes = instr->prototypes(); + ZoneList<Handle<Map> >* maps = instr->maps(); + + ASSERT(prototypes->length() == maps->length()); + + for (int i = 0; i < prototypes->length(); i++) { + __ LoadHeapObject(reg, prototypes->at(i)); + DoCheckMapCommon(reg, maps->at(i), instr); + } +} + + void LCodeGen::DoAllocate(LAllocate* instr) { class DeferredAllocate: public LDeferredCode { public: @@ -5338,8 +5400,6 @@ void LCodeGen::DoDeoptimize(LDeoptimize* instr) { if (info()->IsStub() && type == Deoptimizer::EAGER) { type = Deoptimizer::LAZY; } - - Comment(";;; deoptimize: %s", instr->hydrogen()->reason()); DeoptimizeIf(no_condition, instr->environment(), type); } diff --git a/chromium/v8/src/x64/lithium-codegen-x64.h b/chromium/v8/src/x64/lithium-codegen-x64.h index a74ec7982c4..4286d07de74 100644 --- a/chromium/v8/src/x64/lithium-codegen-x64.h +++ b/chromium/v8/src/x64/lithium-codegen-x64.h @@ -67,8 +67,7 @@ class LCodeGen BASE_EMBEDDED { frame_is_built_(false), safepoints_(info->zone()), resolver_(this), - expected_safepoint_kind_(Safepoint::kSimple), - old_position_(RelocInfo::kNoPosition) { + expected_safepoint_kind_(Safepoint::kSimple) { PopulateDeoptimizationLiteralsWithInlinedFunctions(); } @@ -103,6 +102,7 @@ class LCodeGen BASE_EMBEDDED { XMMRegister ToDoubleRegister(LOperand* op) const; bool IsInteger32Constant(LConstantOperand* op) const; bool IsSmiConstant(LConstantOperand* op) const; + int ToRepresentation(LConstantOperand* op, const Representation& r) const; int32_t ToInteger32(LConstantOperand* op) const; Smi* ToSmi(LConstantOperand* op) const; double ToDouble(LConstantOperand* op) const; @@ -132,7 +132,8 @@ class LCodeGen BASE_EMBEDDED { void DoDeferredAllocate(LAllocate* instr); void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, Label* map_check); - void DoDeferredInstanceMigration(LCheckMaps* instr, Register object); + + void DoCheckMapCommon(Register reg, Handle<Map> map, LInstruction* instr); // Parallel move support. void DoParallelMove(LParallelMove* move); @@ -178,7 +179,7 @@ class LCodeGen BASE_EMBEDDED { int GetStackSlotCount() const { return chunk()->spill_slot_count(); } - void Abort(BailoutReason reason); + void Abort(const char* reason); void FPRINTF_CHECKING Comment(const char* format, ...); void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); } @@ -236,6 +237,7 @@ class LCodeGen BASE_EMBEDDED { CallKind call_kind, RDIState rdi_state); + void RecordSafepointWithLazyDeopt(LInstruction* instr, SafepointMode safepoint_mode, int argc); @@ -246,14 +248,10 @@ class LCodeGen BASE_EMBEDDED { Deoptimizer::BailoutType bailout_type); void DeoptimizeIf(Condition cc, LEnvironment* environment); void ApplyCheckIf(Condition cc, LBoundsCheck* check); - - void AddToTranslation(LEnvironment* environment, - Translation* translation, + void AddToTranslation(Translation* translation, LOperand* op, bool is_tagged, - bool is_uint32, - int* object_index_pointer, - int* dematerialized_index_pointer); + bool is_uint32); void RegisterDependentCodeForEmbeddedMaps(Handle<Code> code); void PopulateDeoptimizationData(Handle<Code> code); int DefineDeoptimizationLiteral(Handle<Object> literal); @@ -270,7 +268,6 @@ class LCodeGen BASE_EMBEDDED { uint32_t additional_index = 0); void EmitIntegerMathAbs(LMathAbs* instr); - void EmitSmiMathAbs(LMathAbs* instr); // Support for recording safepoint and position information. void RecordSafepoint(LPointerMap* pointers, @@ -283,14 +280,11 @@ class LCodeGen BASE_EMBEDDED { int arguments, Safepoint::DeoptMode mode); void RecordPosition(int position); - void RecordAndUpdatePosition(int position); static Condition TokenToCondition(Token::Value op, bool is_unsigned); void EmitGoto(int block); template<class InstrType> void EmitBranch(InstrType instr, Condition cc); - template<class InstrType> - void EmitFalseBranch(InstrType instr, Condition cc); void EmitNumberUntagD( Register input, XMMRegister result, @@ -326,6 +320,12 @@ class LCodeGen BASE_EMBEDDED { // Caller should branch on equal condition. void EmitIsConstructCall(Register temp); + void EmitLoadFieldOrConstantFunction(Register result, + Register object, + Handle<Map> type, + Handle<String> name, + LEnvironment* env); + // Emits code for pushing either a tagged constant, a (non-double) // register, or a stack slot operand. void EmitPushTaggedOperand(LOperand* operand); @@ -382,8 +382,6 @@ class LCodeGen BASE_EMBEDDED { Safepoint::Kind expected_safepoint_kind_; - int old_position_; - class PushSafepointRegistersScope BASE_EMBEDDED { public: explicit PushSafepointRegistersScope(LCodeGen* codegen) diff --git a/chromium/v8/src/x64/lithium-x64.cc b/chromium/v8/src/x64/lithium-x64.cc index c058b0df44a..897af2bca14 100644 --- a/chromium/v8/src/x64/lithium-x64.cc +++ b/chromium/v8/src/x64/lithium-x64.cc @@ -443,7 +443,7 @@ LPlatformChunk* LChunkBuilder::Build() { } -void LCodeGen::Abort(BailoutReason reason) { +void LCodeGen::Abort(const char* reason) { info()->set_bailout_reason(reason); status_ = ABORTED; } @@ -601,10 +601,8 @@ LInstruction* LChunkBuilder::DefineFixedDouble( LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) { HEnvironment* hydrogen_env = current_block_->last_environment(); int argument_index_accumulator = 0; - ZoneList<HValue*> objects_to_materialize(0, zone()); instr->set_environment(CreateEnvironment(hydrogen_env, - &argument_index_accumulator, - &objects_to_materialize)); + &argument_index_accumulator)); return instr; } @@ -656,7 +654,7 @@ LUnallocated* LChunkBuilder::TempRegister() { new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER); int vreg = allocator_->GetVirtualRegister(); if (!allocator_->AllocationOk()) { - Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister); + Abort("Out of virtual registers while trying to allocate temp register."); vreg = 0; } operand->set_virtual_register(vreg); @@ -884,7 +882,6 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { } #endif - instr->set_position(position_); if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) { instr = AssignPointerMap(instr); } @@ -900,13 +897,11 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { LEnvironment* LChunkBuilder::CreateEnvironment( HEnvironment* hydrogen_env, - int* argument_index_accumulator, - ZoneList<HValue*>* objects_to_materialize) { + int* argument_index_accumulator) { if (hydrogen_env == NULL) return NULL; - LEnvironment* outer = CreateEnvironment(hydrogen_env->outer(), - argument_index_accumulator, - objects_to_materialize); + LEnvironment* outer = + CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator); BailoutId ast_id = hydrogen_env->ast_id(); ASSERT(!ast_id.IsNone() || hydrogen_env->frame_type() != JS_FUNCTION); @@ -921,16 +916,16 @@ LEnvironment* LChunkBuilder::CreateEnvironment( outer, hydrogen_env->entry(), zone()); + bool needs_arguments_object_materialization = false; int argument_index = *argument_index_accumulator; - int object_index = objects_to_materialize->length(); for (int i = 0; i < hydrogen_env->length(); ++i) { if (hydrogen_env->is_special_index(i)) continue; - LOperand* op; HValue* value = hydrogen_env->values()->at(i); - if (value->IsArgumentsObject() || value->IsCapturedObject()) { - objects_to_materialize->Add(value, zone()); - op = LEnvironment::materialization_marker(); + LOperand* op = NULL; + if (value->IsArgumentsObject()) { + needs_arguments_object_materialization = true; + op = NULL; } else if (value->IsPushArgument()) { op = new(zone()) LArgument(argument_index++); } else { @@ -941,33 +936,15 @@ LEnvironment* LChunkBuilder::CreateEnvironment( value->CheckFlag(HInstruction::kUint32)); } - for (int i = object_index; i < objects_to_materialize->length(); ++i) { - HValue* object_to_materialize = objects_to_materialize->at(i); - int previously_materialized_object = -1; - for (int prev = 0; prev < i; ++prev) { - if (objects_to_materialize->at(prev) == objects_to_materialize->at(i)) { - previously_materialized_object = prev; - break; - } - } - int length = object_to_materialize->OperandCount(); - bool is_arguments = object_to_materialize->IsArgumentsObject(); - if (previously_materialized_object >= 0) { - result->AddDuplicateObject(previously_materialized_object); - continue; - } else { - result->AddNewObject(is_arguments ? length - 1 : length, is_arguments); - } - for (int i = is_arguments ? 1 : 0; i < length; ++i) { - LOperand* op; - HValue* value = object_to_materialize->OperandAt(i); - if (value->IsArgumentsObject() || value->IsCapturedObject()) { - objects_to_materialize->Add(value, zone()); - op = LEnvironment::materialization_marker(); - } else { - ASSERT(!value->IsPushArgument()); - op = UseAny(value); - } + if (needs_arguments_object_materialization) { + HArgumentsObject* arguments = hydrogen_env->entry() == NULL + ? graph()->GetArgumentsObject() + : hydrogen_env->entry()->arguments_object(); + ASSERT(arguments->IsLinked()); + for (int i = 1; i < arguments->arguments_count(); ++i) { + HValue* value = arguments->arguments_values()->at(i); + ASSERT(!value->IsArgumentsObject() && !value->IsPushArgument()); + LOperand* op = UseAny(value); result->AddValue(op, value->representation(), value->CheckFlag(HInstruction::kUint32)); @@ -1344,6 +1321,16 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { } +LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) { + ASSERT(instr->value()->representation().IsInteger32()); + ASSERT(instr->representation().IsInteger32()); + if (instr->HasNoUses()) return NULL; + LOperand* input = UseRegisterAtStart(instr->value()); + LBitNotI* result = new(zone()) LBitNotI(input); + return DefineSameAsFirst(result); +} + + LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { if (instr->representation().IsDouble()) { return DoArithmeticD(Token::DIV, instr); @@ -1612,8 +1599,9 @@ LInstruction* LChunkBuilder::DoCompareNumericAndBranch( HCompareNumericAndBranch* instr) { Representation r = instr->representation(); if (r.IsSmiOrInteger32()) { - ASSERT(instr->left()->representation().Equals(r)); - ASSERT(instr->right()->representation().Equals(r)); + ASSERT(instr->left()->representation().IsSmiOrInteger32()); + ASSERT(instr->left()->representation().Equals( + instr->right()->representation())); LOperand* left = UseRegisterOrConstantAtStart(instr->left()); LOperand* right = UseOrConstantAtStart(instr->right()); return new(zone()) LCompareNumericAndBranch(left, right); @@ -1643,13 +1631,6 @@ LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch( } -LInstruction* LChunkBuilder::DoCompareHoleAndBranch( - HCompareHoleAndBranch* instr) { - LOperand* object = UseRegisterAtStart(instr->object()); - return new(zone()) LCmpHoleAndBranch(object); -} - - LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) { ASSERT(instr->value()->representation().IsTagged()); return new(zone()) LIsObjectAndBranch(UseRegisterAtStart(instr->value())); @@ -1764,6 +1745,17 @@ LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) { } +LInstruction* LChunkBuilder::DoNumericConstraint(HNumericConstraint* instr) { + return NULL; +} + + +LInstruction* LChunkBuilder::DoInductionVariableAnnotation( + HInductionVariableAnnotation* instr) { + return NULL; +} + + LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { LOperand* value = UseRegisterOrConstantAtStart(instr->index()); LOperand* length = Use(instr->length()); @@ -1928,6 +1920,15 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { } +LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) { + LUnallocated* temp = NULL; + if (!instr->CanOmitPrototypeChecks()) temp = TempRegister(); + LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp); + if (instr->CanOmitPrototypeChecks()) return result; + return AssignEnvironment(result); +} + + LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { LOperand* value = UseRegisterAtStart(instr->value()); return AssignEnvironment(new(zone()) LCheckFunction(value)); @@ -1936,16 +1937,10 @@ LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) { LOperand* value = NULL; - if (!instr->CanOmitMapChecks()) { - value = UseRegisterAtStart(instr->value()); - if (instr->has_migration_target()) info()->MarkAsDeferredCalling(); - } + if (!instr->CanOmitMapChecks()) value = UseRegisterAtStart(instr->value()); LCheckMaps* result = new(zone()) LCheckMaps(value); - if (!instr->CanOmitMapChecks()) { - AssignEnvironment(result); - if (instr->has_migration_target()) return AssignPointerMap(result); - } - return result; + if (instr->CanOmitMapChecks()) return result; + return AssignEnvironment(result); } @@ -2065,6 +2060,23 @@ LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) { } +LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic( + HLoadNamedFieldPolymorphic* instr) { + ASSERT(instr->representation().IsTagged()); + if (instr->need_generic()) { + LOperand* obj = UseFixed(instr->object(), rax); + LLoadNamedFieldPolymorphic* result = + new(zone()) LLoadNamedFieldPolymorphic(obj); + return MarkAsCall(DefineFixed(result, rax), instr); + } else { + LOperand* obj = UseRegisterAtStart(instr->object()); + LLoadNamedFieldPolymorphic* result = + new(zone()) LLoadNamedFieldPolymorphic(obj); + return AssignEnvironment(DefineAsRegister(result)); + } +} + + LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { LOperand* object = UseFixed(instr->object(), rax); LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric(object); @@ -2221,7 +2233,7 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) { bool is_external_location = instr->access().IsExternalMemory() && instr->access().offset() == 0; bool needs_write_barrier = instr->NeedsWriteBarrier(); - bool needs_write_barrier_for_map = instr->has_transition() && + bool needs_write_barrier_for_map = !instr->transition().is_null() && instr->NeedsWriteBarrierForMap(); LOperand* obj; @@ -2356,7 +2368,7 @@ LInstruction* LChunkBuilder::DoParameter(HParameter* instr) { LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) { int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width. if (spill_index > LUnallocated::kMaxFixedSlotIndex) { - Abort(kTooManySpillSlotsNeededForOSR); + Abort("Too many spill slots needed for OSR"); spill_index = 0; } return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index); @@ -2378,12 +2390,6 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) { } -LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) { - // There are no real uses of a captured object. - return NULL; -} - - LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) { info()->MarkAsRequiresFrame(); LOperand* args = UseRegister(instr->arguments()); diff --git a/chromium/v8/src/x64/lithium-x64.h b/chromium/v8/src/x64/lithium-x64.h index 77bebe64bd7..31e54370e0a 100644 --- a/chromium/v8/src/x64/lithium-x64.h +++ b/chromium/v8/src/x64/lithium-x64.h @@ -50,6 +50,7 @@ class LCodeGen; V(ArithmeticD) \ V(ArithmeticT) \ V(BitI) \ + V(BitNotI) \ V(BoundsCheck) \ V(Branch) \ V(CallConstantFunction) \ @@ -67,6 +68,7 @@ class LCodeGen; V(CheckMaps) \ V(CheckMapValue) \ V(CheckNonSmi) \ + V(CheckPrototypeMaps) \ V(CheckSmi) \ V(ClampDToUint8) \ V(ClampIToUint8) \ @@ -74,7 +76,6 @@ class LCodeGen; V(ClassOfTestAndBranch) \ V(CompareNumericAndBranch) \ V(CmpObjectEqAndBranch) \ - V(CmpHoleAndBranch) \ V(CmpMapAndBranch) \ V(CmpT) \ V(ConstantD) \ @@ -127,6 +128,7 @@ class LCodeGen; V(LoadKeyed) \ V(LoadKeyedGeneric) \ V(LoadNamedField) \ + V(LoadNamedFieldPolymorphic) \ V(LoadNamedGeneric) \ V(MapEnumLength) \ V(MathAbs) \ @@ -205,11 +207,9 @@ class LCodeGen; class LInstruction: public ZoneObject { public: LInstruction() - : environment_(NULL), - hydrogen_value_(NULL), - bit_field_(IsCallBits::encode(false)) { - set_position(RelocInfo::kNoPosition); - } + : environment_(NULL), + hydrogen_value_(NULL), + is_call_(false) { } virtual ~LInstruction() { } @@ -249,30 +249,20 @@ class LInstruction: public ZoneObject { LPointerMap* pointer_map() const { return pointer_map_.get(); } bool HasPointerMap() const { return pointer_map_.is_set(); } - // The 31 bits PositionBits is used to store the int position value. And the - // position value may be RelocInfo::kNoPosition (-1). The accessor always - // +1/-1 so that the encoded value of position in bit_field_ is always >= 0 - // and can fit into the 31 bits PositionBits. - void set_position(int pos) { - bit_field_ = PositionBits::update(bit_field_, pos + 1); - } - int position() { return PositionBits::decode(bit_field_) - 1; } - void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; } HValue* hydrogen_value() const { return hydrogen_value_; } - void MarkAsCall() { bit_field_ = IsCallBits::update(bit_field_, true); } - bool IsCall() const { return IsCallBits::decode(bit_field_); } + void MarkAsCall() { is_call_ = true; } // Interface to the register allocator and iterators. - bool ClobbersTemps() const { return IsCall(); } - bool ClobbersRegisters() const { return IsCall(); } - bool ClobbersDoubleRegisters() const { return IsCall(); } + bool ClobbersTemps() const { return is_call_; } + bool ClobbersRegisters() const { return is_call_; } + bool ClobbersDoubleRegisters() const { return is_call_; } virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { } // Interface to the register allocator and iterators. - bool IsMarkedAsCall() const { return IsCall(); } + bool IsMarkedAsCall() const { return is_call_; } virtual bool HasResult() const = 0; virtual LOperand* result() const = 0; @@ -296,13 +286,10 @@ class LInstruction: public ZoneObject { virtual int TempCount() = 0; virtual LOperand* TempAt(int i) = 0; - class IsCallBits: public BitField<bool, 0, 1> {}; - class PositionBits: public BitField<int, 1, 31> {}; - LEnvironment* environment_; SetOncePointer<LPointerMap> pointer_map_; HValue* hydrogen_value_; - int bit_field_; + bool is_call_; }; @@ -838,20 +825,8 @@ class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> { LOperand* left() { return inputs_[0]; } LOperand* right() { return inputs_[1]; } - DECLARE_CONCRETE_INSTRUCTION(CmpObjectEqAndBranch, "cmp-object-eq-and-branch") -}; - - -class LCmpHoleAndBranch: public LControlInstruction<1, 0> { - public: - explicit LCmpHoleAndBranch(LOperand* object) { - inputs_[0] = object; - } - - LOperand* object() { return inputs_[0]; } - - DECLARE_CONCRETE_INSTRUCTION(CmpHoleAndBranch, "cmp-hole-and-branch") - DECLARE_HYDROGEN_ACCESSOR(CompareHoleAndBranch) + DECLARE_CONCRETE_INSTRUCTION(CmpObjectEqAndBranch, + "cmp-object-eq-and-branch") }; @@ -1337,6 +1312,18 @@ class LThrow: public LTemplateInstruction<0, 1, 0> { }; +class LBitNotI: public LTemplateInstruction<1, 1, 0> { + public: + explicit LBitNotI(LOperand* value) { + inputs_[0] = value; + } + + LOperand* value() { return inputs_[0]; } + + DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i") +}; + + class LAddI: public LTemplateInstruction<1, 2, 0> { public: LAddI(LOperand* left, LOperand* right) { @@ -1478,6 +1465,19 @@ class LLoadNamedField: public LTemplateInstruction<1, 1, 0> { }; +class LLoadNamedFieldPolymorphic: public LTemplateInstruction<1, 1, 0> { + public: + explicit LLoadNamedFieldPolymorphic(LOperand* object) { + inputs_[0] = object; + } + + DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field-polymorphic") + DECLARE_HYDROGEN_ACCESSOR(LoadNamedFieldPolymorphic) + + LOperand* object() { return inputs_[0]; } +}; + + class LLoadNamedGeneric: public LTemplateInstruction<1, 1, 0> { public: explicit LLoadNamedGeneric(LOperand* object) { @@ -2066,7 +2066,7 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 1> { virtual void PrintDataTo(StringStream* stream); - Handle<Map> transition() const { return hydrogen()->transition_map(); } + Handle<Map> transition() const { return hydrogen()->transition(); } Representation representation() const { return hydrogen()->field_representation(); } @@ -2262,6 +2262,24 @@ class LCheckMaps: public LTemplateInstruction<0, 1, 0> { }; +class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 1> { + public: + explicit LCheckPrototypeMaps(LOperand* temp) { + temps_[0] = temp; + } + + LOperand* temp() { return temps_[0]; } + + DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps") + DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps) + + ZoneList<Handle<JSObject> >* prototypes() const { + return hydrogen()->prototypes(); + } + ZoneList<Handle<Map> >* maps() const { return hydrogen()->maps(); } +}; + + class LCheckSmi: public LTemplateInstruction<1, 1, 0> { public: explicit LCheckSmi(LOperand* value) { @@ -2555,7 +2573,7 @@ class LChunkBuilder BASE_EMBEDDED { bool is_done() const { return status_ == DONE; } bool is_aborted() const { return status_ == ABORTED; } - void Abort(BailoutReason reason); + void Abort(const char* reason); // Methods for getting operands for Use / Define / Temp. LUnallocated* ToUnallocated(Register reg); @@ -2641,8 +2659,7 @@ class LChunkBuilder BASE_EMBEDDED { CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY); LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, - int* argument_index_accumulator, - ZoneList<HValue*>* objects_to_materialize); + int* argument_index_accumulator); void VisitInstruction(HInstruction* current); diff --git a/chromium/v8/src/x64/macro-assembler-x64.cc b/chromium/v8/src/x64/macro-assembler-x64.cc index 9c9b1620e58..13d7ddaa685 100644 --- a/chromium/v8/src/x64/macro-assembler-x64.cc +++ b/chromium/v8/src/x64/macro-assembler-x64.cc @@ -155,7 +155,7 @@ int MacroAssembler::LoadAddressSize(ExternalReference source) { } } // Size of movq(destination, src); - return Assembler::kMoveAddressIntoScratchRegisterInstructionLength; + return 10; } @@ -449,8 +449,8 @@ void MacroAssembler::RecordWrite(Register object, } -void MacroAssembler::Assert(Condition cc, BailoutReason reason) { - if (emit_debug_code()) Check(cc, reason); +void MacroAssembler::Assert(Condition cc, const char* msg) { + if (emit_debug_code()) Check(cc, msg); } @@ -466,16 +466,16 @@ void MacroAssembler::AssertFastElements(Register elements) { CompareRoot(FieldOperand(elements, HeapObject::kMapOffset), Heap::kFixedCOWArrayMapRootIndex); j(equal, &ok, Label::kNear); - Abort(kJSObjectWithFastElementsMapHasSlowElements); + Abort("JSObject with fast elements map has slow elements"); bind(&ok); } } -void MacroAssembler::Check(Condition cc, BailoutReason reason) { +void MacroAssembler::Check(Condition cc, const char* msg) { Label L; j(cc, &L, Label::kNear); - Abort(reason); + Abort(msg); // Control will not return here. bind(&L); } @@ -508,13 +508,12 @@ void MacroAssembler::NegativeZeroTest(Register result, } -void MacroAssembler::Abort(BailoutReason reason) { +void MacroAssembler::Abort(const char* msg) { // We want to pass the msg string like a smi to avoid GC // problems, however msg is not guaranteed to be aligned // properly. Instead, we pass an aligned pointer that is // a proper v8 smi, but also pass the alignment difference // from the real pointer as a smi. - const char* msg = GetBailoutReason(reason); intptr_t p1 = reinterpret_cast<intptr_t>(msg); intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag; // Note: p0 might not be a valid Smi _value_, but it has a valid Smi tag. @@ -839,7 +838,7 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address, CompareRoot(return_value, Heap::kNullValueRootIndex); j(equal, &ok, Label::kNear); - Abort(kAPICallReturnedInvalidObject); + Abort("API call returned invalid object"); bind(&ok); #endif @@ -1039,7 +1038,7 @@ void MacroAssembler::LoadSmiConstant(Register dst, Smi* source) { RelocInfo::NONE64); cmpq(dst, kSmiConstantRegister); if (allow_stub_calls()) { - Assert(equal, kUninitializedKSmiConstantRegister); + Assert(equal, "Uninitialized kSmiConstantRegister"); } else { Label ok; j(equal, &ok, Label::kNear); @@ -1107,7 +1106,7 @@ void MacroAssembler::Integer32ToSmiField(const Operand& dst, Register src) { Label ok; j(zero, &ok, Label::kNear); if (allow_stub_calls()) { - Abort(kInteger32ToSmiFieldWritingToNonSmiLocation); + Abort("Integer32ToSmiField writing to non-smi location"); } else { int3(); } @@ -1690,12 +1689,12 @@ void MacroAssembler::SmiAdd(Register dst, if (emit_debug_code()) { movq(kScratchRegister, src1); addq(kScratchRegister, src2); - Check(no_overflow, kSmiAdditionOverflow); + Check(no_overflow, "Smi addition overflow"); } lea(dst, Operand(src1, src2, times_1, 0)); } else { addq(dst, src2); - Assert(no_overflow, kSmiAdditionOverflow); + Assert(no_overflow, "Smi addition overflow"); } } @@ -1727,7 +1726,7 @@ void MacroAssembler::SmiSub(Register dst, Register src1, Register src2) { movq(dst, src1); } subq(dst, src2); - Assert(no_overflow, kSmiSubtractionOverflow); + Assert(no_overflow, "Smi subtraction overflow"); } @@ -1759,7 +1758,7 @@ void MacroAssembler::SmiSub(Register dst, movq(dst, src1); } subq(dst, src2); - Assert(no_overflow, kSmiSubtractionOverflow); + Assert(no_overflow, "Smi subtraction overflow"); } @@ -2156,7 +2155,7 @@ void MacroAssembler::SelectNonSmi(Register dst, #ifdef DEBUG if (allow_stub_calls()) { // Check contains a stub call. Condition not_both_smis = NegateCondition(CheckBothSmi(src1, src2)); - Check(not_both_smis, kBothRegistersWereSmisInSelectNonSmi); + Check(not_both_smis, "Both registers were smis in SelectNonSmi."); } #endif STATIC_ASSERT(kSmiTag == 0); @@ -2511,8 +2510,8 @@ void MacroAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) { int MacroAssembler::CallSize(ExternalReference ext) { // Opcode for call kScratchRegister is: Rex.B FF D4 (three bytes). - return LoadAddressSize(ext) + - Assembler::kCallScratchRegisterInstructionLength; + const int kCallInstructionSize = 3; + return LoadAddressSize(ext) + kCallInstructionSize; } @@ -2799,9 +2798,9 @@ void MacroAssembler::Ret(int bytes_dropped, Register scratch) { if (is_uint16(bytes_dropped)) { ret(bytes_dropped); } else { - PopReturnAddressTo(scratch); + pop(scratch); addq(rsp, Immediate(bytes_dropped)); - PushReturnAddressFrom(scratch); + push(scratch); ret(0); } } @@ -2985,7 +2984,7 @@ void MacroAssembler::LoadUint32(XMMRegister dst, XMMRegister scratch) { if (FLAG_debug_code) { cmpq(src, Immediate(0xffffffff)); - Assert(below_equal, kInputGPRIsExpectedToHaveUpper32Cleared); + Assert(below_equal, "input GPR is expected to have upper32 cleared"); } cvtqsi2sd(dst, src); } @@ -3034,7 +3033,7 @@ void MacroAssembler::AssertNumber(Register object) { j(is_smi, &ok, Label::kNear); Cmp(FieldOperand(object, HeapObject::kMapOffset), isolate()->factory()->heap_number_map()); - Check(equal, kOperandIsNotANumber); + Check(equal, "Operand is not a number"); bind(&ok); } } @@ -3043,7 +3042,7 @@ void MacroAssembler::AssertNumber(Register object) { void MacroAssembler::AssertNotSmi(Register object) { if (emit_debug_code()) { Condition is_smi = CheckSmi(object); - Check(NegateCondition(is_smi), kOperandIsASmi); + Check(NegateCondition(is_smi), "Operand is a smi"); } } @@ -3051,7 +3050,7 @@ void MacroAssembler::AssertNotSmi(Register object) { void MacroAssembler::AssertSmi(Register object) { if (emit_debug_code()) { Condition is_smi = CheckSmi(object); - Check(is_smi, kOperandIsNotASmi); + Check(is_smi, "Operand is not a smi"); } } @@ -3059,7 +3058,7 @@ void MacroAssembler::AssertSmi(Register object) { void MacroAssembler::AssertSmi(const Operand& object) { if (emit_debug_code()) { Condition is_smi = CheckSmi(object); - Check(is_smi, kOperandIsNotASmi); + Check(is_smi, "Operand is not a smi"); } } @@ -3069,7 +3068,7 @@ void MacroAssembler::AssertZeroExtended(Register int32_register) { ASSERT(!int32_register.is(kScratchRegister)); movq(kScratchRegister, 0x100000000l, RelocInfo::NONE64); cmpq(kScratchRegister, int32_register); - Check(above_equal, k32BitValueInRegisterIsNotZeroExtended); + Check(above_equal, "32 bit value in register is not zero-extended"); } } @@ -3077,12 +3076,12 @@ void MacroAssembler::AssertZeroExtended(Register int32_register) { void MacroAssembler::AssertString(Register object) { if (emit_debug_code()) { testb(object, Immediate(kSmiTagMask)); - Check(not_equal, kOperandIsASmiAndNotAString); + Check(not_equal, "Operand is a smi and not a string"); push(object); movq(object, FieldOperand(object, HeapObject::kMapOffset)); CmpInstanceType(object, FIRST_NONSTRING_TYPE); pop(object); - Check(below, kOperandIsNotAString); + Check(below, "Operand is not a string"); } } @@ -3090,24 +3089,24 @@ void MacroAssembler::AssertString(Register object) { void MacroAssembler::AssertName(Register object) { if (emit_debug_code()) { testb(object, Immediate(kSmiTagMask)); - Check(not_equal, kOperandIsASmiAndNotAName); + Check(not_equal, "Operand is a smi and not a name"); push(object); movq(object, FieldOperand(object, HeapObject::kMapOffset)); CmpInstanceType(object, LAST_NAME_TYPE); pop(object); - Check(below_equal, kOperandIsNotAName); + Check(below_equal, "Operand is not a name"); } } void MacroAssembler::AssertRootValue(Register src, Heap::RootListIndex root_value_index, - BailoutReason reason) { + const char* message) { if (emit_debug_code()) { ASSERT(!src.is(kScratchRegister)); LoadRoot(kScratchRegister, root_value_index); cmpq(src, kScratchRegister); - Check(equal, reason); + Check(equal, message); } } @@ -3458,7 +3457,7 @@ void MacroAssembler::EnterFrame(StackFrame::Type type) { isolate()->factory()->undefined_value(), RelocInfo::EMBEDDED_OBJECT); cmpq(Operand(rsp, 0), kScratchRegister); - Check(not_equal, kCodeObjectNotProperlyPatched); + Check(not_equal, "code object not properly patched"); } } @@ -3467,7 +3466,7 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) { if (emit_debug_code()) { Move(kScratchRegister, Smi::FromInt(type)); cmpq(Operand(rbp, StandardFrameConstants::kMarkerOffset), kScratchRegister); - Check(equal, kStackFrameTypesMustMatch); + Check(equal, "stack frame types must match"); } movq(rsp, rbp); pop(rbp); @@ -3568,7 +3567,8 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles) { // from the caller stack. lea(rsp, Operand(r15, 1 * kPointerSize)); - PushReturnAddressFrom(rcx); + // Push the return address to get ready to return. + push(rcx); LeaveExitFrameEpilogue(); } @@ -3612,7 +3612,7 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, // When generating debug code, make sure the lexical context is set. if (emit_debug_code()) { cmpq(scratch, Immediate(0)); - Check(not_equal, kWeShouldNotHaveAnEmptyLexicalContext); + Check(not_equal, "we should not have an empty lexical context"); } // Load the native context of the current context. int offset = @@ -3624,7 +3624,7 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, if (emit_debug_code()) { Cmp(FieldOperand(scratch, HeapObject::kMapOffset), isolate()->factory()->native_context_map()); - Check(equal, kJSGlobalObjectNativeContextShouldBeANativeContext); + Check(equal, "JSGlobalObject::native_context should be a native context."); } // Check if both contexts are the same. @@ -3643,12 +3643,12 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, movq(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); CompareRoot(holder_reg, Heap::kNullValueRootIndex); - Check(not_equal, kJSGlobalProxyContextShouldNotBeNull); + Check(not_equal, "JSGlobalProxy::context() should not be null."); // Read the first word and compare to native_context_map(), movq(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset)); CompareRoot(holder_reg, Heap::kNativeContextMapRootIndex); - Check(equal, kJSGlobalObjectNativeContextShouldBeANativeContext); + Check(equal, "JSGlobalObject::native_context should be a native context."); pop(holder_reg); } @@ -3794,7 +3794,7 @@ void MacroAssembler::LoadAllocationTopHelper(Register result, // Assert that result actually contains top on entry. Operand top_operand = ExternalOperand(allocation_top); cmpq(result, top_operand); - Check(equal, kUnexpectedAllocationTop); + Check(equal, "Unexpected allocation top"); #endif return; } @@ -3815,7 +3815,7 @@ void MacroAssembler::UpdateAllocationTopHelper(Register result_end, AllocationFlags flags) { if (emit_debug_code()) { testq(result_end, Immediate(kObjectAlignmentMask)); - Check(zero, kUnalignedAllocationInNewSpace); + Check(zero, "Unaligned allocation in new space"); } ExternalReference allocation_top = @@ -3862,7 +3862,7 @@ void MacroAssembler::Allocate(int object_size, // always safe because the limit of the heap is always aligned. if (((flags & DOUBLE_ALIGNMENT) != 0) && FLAG_debug_code) { testq(result, Immediate(kDoubleAlignmentMask)); - Check(zero, kAllocationIsNotDoubleAligned); + Check(zero, "Allocation is not double aligned"); } // Calculate new top and bail out if new space is exhausted. @@ -3941,7 +3941,7 @@ void MacroAssembler::Allocate(Register object_size, // always safe because the limit of the heap is always aligned. if (((flags & DOUBLE_ALIGNMENT) != 0) && FLAG_debug_code) { testq(result, Immediate(kDoubleAlignmentMask)); - Check(zero, kAllocationIsNotDoubleAligned); + Check(zero, "Allocation is not double aligned"); } // Calculate new top and bail out if new space is exhausted. @@ -3975,7 +3975,7 @@ void MacroAssembler::UndoAllocationInNewSpace(Register object) { Operand top_operand = ExternalOperand(new_space_allocation_top); #ifdef DEBUG cmpq(object, top_operand); - Check(below, kUndoAllocationOfNonAllocatedMemory); + Check(below, "Undo allocation of non allocated memory"); #endif movq(top_operand, object); } @@ -4165,7 +4165,7 @@ void MacroAssembler::CopyBytes(Register destination, ASSERT(min_length >= 0); if (emit_debug_code()) { cmpl(length, Immediate(min_length)); - Assert(greater_equal, kInvalidMinLength); + Assert(greater_equal, "Invalid min_length"); } Label loop, done, short_string, short_loop; @@ -4249,7 +4249,7 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) { if (emit_debug_code()) { CompareRoot(FieldOperand(dst, HeapObject::kMapOffset), Heap::kWithContextMapRootIndex); - Check(not_equal, kVariableResolvedToWithContext); + Check(not_equal, "Variable resolved to with context."); } } @@ -4340,7 +4340,7 @@ void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, CheckMap(map, isolate()->factory()->meta_map(), &fail, DO_SMI_CHECK); jmp(&ok); bind(&fail); - Abort(kGlobalFunctionsMustHaveInitialMap); + Abort("Global functions must have initial map"); bind(&ok); } } diff --git a/chromium/v8/src/x64/macro-assembler-x64.h b/chromium/v8/src/x64/macro-assembler-x64.h index 61abc206e10..e611c8ae279 100644 --- a/chromium/v8/src/x64/macro-assembler-x64.h +++ b/chromium/v8/src/x64/macro-assembler-x64.h @@ -823,10 +823,6 @@ class MacroAssembler: public Assembler { void Drop(int stack_elements); void Call(Label* target) { call(target); } - void Push(Register src) { push(src); } - void Pop(Register dst) { pop(dst); } - void PushReturnAddressFrom(Register src) { push(src); } - void PopReturnAddressTo(Register dst) { pop(dst); } // Control Flow void Jump(Address destination, RelocInfo::Mode rmode); @@ -841,7 +837,7 @@ class MacroAssembler: public Assembler { // The size of the code generated for different call instructions. int CallSize(Address destination, RelocInfo::Mode rmode) { - return kCallSequenceLength; + return kCallInstructionLength; } int CallSize(ExternalReference ext); int CallSize(Handle<Code> code_object) { @@ -1006,7 +1002,7 @@ class MacroAssembler: public Assembler { // enabled via --debug-code. void AssertRootValue(Register src, Heap::RootListIndex root_value_index, - BailoutReason reason); + const char* message); // --------------------------------------------------------------------------- // Exception handling @@ -1323,15 +1319,15 @@ class MacroAssembler: public Assembler { // Calls Abort(msg) if the condition cc is not satisfied. // Use --debug_code to enable. - void Assert(Condition cc, BailoutReason reason); + void Assert(Condition cc, const char* msg); void AssertFastElements(Register elements); // Like Assert(), but always enabled. - void Check(Condition cc, BailoutReason reason); + void Check(Condition cc, const char* msg); // Print a message to stdout and abort execution. - void Abort(BailoutReason msg); + void Abort(const char* msg); // Check that the stack is aligned. void CheckStackAlignment(); diff --git a/chromium/v8/src/x64/regexp-macro-assembler-x64.cc b/chromium/v8/src/x64/regexp-macro-assembler-x64.cc index dcd317c666e..106ffb76da5 100644 --- a/chromium/v8/src/x64/regexp-macro-assembler-x64.cc +++ b/chromium/v8/src/x64/regexp-macro-assembler-x64.cc @@ -397,7 +397,7 @@ void RegExpMacroAssemblerX64::CheckNotBackReference( // Fail on partial or illegal capture (start of capture after end of capture). // This must not happen (no back-reference can reference a capture that wasn't // closed before in the reg-exp). - __ Check(greater_equal, kInvalidCaptureReferenced); + __ Check(greater_equal, "Invalid capture referenced"); // Succeed on empty capture (including non-participating capture) __ j(equal, &fallthrough); diff --git a/chromium/v8/src/x64/stub-cache-x64.cc b/chromium/v8/src/x64/stub-cache-x64.cc index 34a557bd1af..39ff656ec45 100644 --- a/chromium/v8/src/x64/stub-cache-x64.cc +++ b/chromium/v8/src/x64/stub-cache-x64.cc @@ -830,11 +830,11 @@ void BaseStoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm, object->map()->unused_property_fields() == 0) { // The properties must be extended before we can store the value. // We jump to a runtime call that extends the properties array. - __ PopReturnAddressTo(scratch1); + __ pop(scratch1); // Return address. __ push(receiver_reg); __ Push(transition); __ push(value_reg); - __ PushReturnAddressFrom(scratch1); + __ push(scratch1); __ TailCallExternalReference( ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), masm->isolate()), @@ -1284,7 +1284,7 @@ void BaseLoadStubCompiler::GenerateLoadCallback( Handle<ExecutableAccessorInfo> callback) { // Insert additional parameters into the stack frame above return address. ASSERT(!scratch4().is(reg)); - __ PopReturnAddressTo(scratch4()); + __ pop(scratch4()); // Get return address to place it below. __ push(receiver()); // receiver __ push(reg); // holder @@ -1324,7 +1324,7 @@ void BaseLoadStubCompiler::GenerateLoadCallback( ASSERT(!name_arg.is(scratch4())); __ movq(name_arg, rsp); - __ PushReturnAddressFrom(scratch4()); + __ push(scratch4()); // Restore return address. // v8::Arguments::values_ and handler for name. const int kStackSpace = PropertyCallbackArguments::kArgsLength + 1; @@ -1444,10 +1444,10 @@ void BaseLoadStubCompiler::GenerateLoadInterceptor( } else { // !compile_followup_inline // Call the runtime system to load the interceptor. // Check that the maps haven't changed. - __ PopReturnAddressTo(scratch2()); + __ pop(scratch2()); // save old return address PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), interceptor_holder); - __ PushReturnAddressFrom(scratch2()); + __ push(scratch2()); // restore old return address ExternalReference ref = ExternalReference( IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate()); @@ -2246,25 +2246,26 @@ Handle<Code> CallStubCompiler::CompileMathAbsCall( Label not_smi; STATIC_ASSERT(kSmiTag == 0); __ JumpIfNotSmi(rax, ¬_smi); + __ SmiToInteger32(rax, rax); - // Branchless abs implementation, refer to below: - // http://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0 // otherwise. - __ movq(rbx, rax); - __ sar(rbx, Immediate(kBitsPerPointer - 1)); + __ movl(rbx, rax); + __ sarl(rbx, Immediate(kBitsPerInt - 1)); // Do bitwise not or do nothing depending on ebx. - __ xor_(rax, rbx); + __ xorl(rax, rbx); // Add 1 or do nothing depending on ebx. - __ subq(rax, rbx); + __ subl(rax, rbx); // If the result is still negative, go to the slow case. // This only happens for the most negative smi. Label slow; __ j(negative, &slow); + // Smi case done. + __ Integer32ToSmi(rax, rax); __ ret(2 * kPointerSize); // Check if the argument is a heap number and load its value. @@ -2649,12 +2650,12 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback( HandlerFrontend(object, receiver(), holder, name, &success); __ bind(&success); - __ PopReturnAddressTo(scratch1()); + __ pop(scratch1()); // remove the return address __ push(receiver()); __ Push(callback); // callback info __ Push(name); __ push(value()); - __ PushReturnAddressFrom(scratch1()); + __ push(scratch1()); // restore return address // Do tail-call to the runtime system. ExternalReference store_callback_property = @@ -2716,12 +2717,12 @@ void StoreStubCompiler::GenerateStoreViaSetter( Handle<Code> StoreStubCompiler::CompileStoreInterceptor( Handle<JSObject> object, Handle<Name> name) { - __ PopReturnAddressTo(scratch1()); + __ pop(scratch1()); // remove the return address __ push(receiver()); __ push(this->name()); __ push(value()); __ Push(Smi::FromInt(strict_mode())); - __ PushReturnAddressFrom(scratch1()); + __ push(scratch1()); // restore return address // Do tail-call to the runtime system. ExternalReference store_ic_property = @@ -2937,7 +2938,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal( __ j(equal, &miss); } else if (FLAG_debug_code) { __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); - __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); + __ Check(not_equal, "DontDelete cells can't contain the hole"); } HandlerFrontendFooter(name, &success, &miss); diff --git a/chromium/v8/src/zone-inl.h b/chromium/v8/src/zone-inl.h index f257382a2db..49e7626f74e 100644 --- a/chromium/v8/src/zone-inl.h +++ b/chromium/v8/src/zone-inl.h @@ -109,12 +109,6 @@ void* ZoneList<T>::operator new(size_t size, Zone* zone) { } -template <typename T> -void* ZoneSplayTree<T>::operator new(size_t size, Zone* zone) { - return zone->New(static_cast<int>(size)); -} - - } } // namespace v8::internal #endif // V8_ZONE_INL_H_ diff --git a/chromium/v8/src/zone.h b/chromium/v8/src/zone.h index bd7cc39b0c4..a12ed793123 100644 --- a/chromium/v8/src/zone.h +++ b/chromium/v8/src/zone.h @@ -177,7 +177,6 @@ struct ZoneAllocationPolicy { explicit ZoneAllocationPolicy(Zone* zone) : zone_(zone) { } INLINE(void* New(size_t size)); INLINE(static void Delete(void *pointer)) { } - Zone* zone() { return zone_; } private: Zone* zone_; @@ -202,7 +201,7 @@ class ZoneList: public List<T, ZoneAllocationPolicy> { ZoneList(const ZoneList<T>& other, Zone* zone) : List<T, ZoneAllocationPolicy>(other.length(), ZoneAllocationPolicy(zone)) { - AddAll(other, zone); + AddAll(other, ZoneAllocationPolicy(zone)); } // We add some convenience wrappers so that we can pass in a Zone @@ -210,7 +209,8 @@ class ZoneList: public List<T, ZoneAllocationPolicy> { INLINE(void Add(const T& element, Zone* zone)) { List<T, ZoneAllocationPolicy>::Add(element, ZoneAllocationPolicy(zone)); } - INLINE(void AddAll(const List<T, ZoneAllocationPolicy>& other, Zone* zone)) { + INLINE(void AddAll(const List<T, ZoneAllocationPolicy>& other, + Zone* zone)) { List<T, ZoneAllocationPolicy>::AddAll(other, ZoneAllocationPolicy(zone)); } INLINE(void AddAll(const Vector<T>& other, Zone* zone)) { @@ -246,11 +246,6 @@ class ZoneSplayTree: public SplayTree<Config, ZoneAllocationPolicy> { explicit ZoneSplayTree(Zone* zone) : SplayTree<Config, ZoneAllocationPolicy>(ZoneAllocationPolicy(zone)) {} ~ZoneSplayTree(); - - INLINE(void* operator new(size_t size, Zone* zone)); - - void operator delete(void* pointer) { UNREACHABLE(); } - void operator delete(void* pointer, Zone* zone) { UNREACHABLE(); } }; diff --git a/chromium/v8/tools/gcmole/Makefile b/chromium/v8/tools/gcmole/Makefile index 764245caf61..23c029c2dc3 100644 --- a/chromium/v8/tools/gcmole/Makefile +++ b/chromium/v8/tools/gcmole/Makefile @@ -40,4 +40,4 @@ libgcmole.so: gcmole.cc -shared -o libgcmole.so gcmole.cc clean: - rm -f libgcmole.so + rm libgcmole.so diff --git a/chromium/v8/tools/gcmole/bootstrap.sh b/chromium/v8/tools/gcmole/bootstrap.sh deleted file mode 100755 index baa0b1f5f54..00000000000 --- a/chromium/v8/tools/gcmole/bootstrap.sh +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2013 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. - -# This script will build libgcmole.so. - -CLANG_RELEASE=2.9 - -THIS_DIR="$(dirname "${0}")" -LLVM_DIR="${THIS_DIR}/../../third_party/llvm" -CLANG_DIR="${LLVM_DIR}/tools/clang" - -LLVM_REPO_URL=${LLVM_URL:-https://llvm.org/svn/llvm-project} - -# Die if any command dies. -set -e - -OS="$(uname -s)" - -# Xcode and clang don't get along when predictive compilation is enabled. -# http://crbug.com/96315 -if [[ "${OS}" = "Darwin" ]] && xcodebuild -version | grep -q 'Xcode 3.2' ; then - XCONF=com.apple.Xcode - if [[ "${GYP_GENERATORS}" != "make" ]] && \ - [ "$(defaults read "${XCONF}" EnablePredictiveCompilation)" != "0" ]; then - echo - echo " HEARKEN!" - echo "You're using Xcode3 and you have 'Predictive Compilation' enabled." - echo "This does not work well with clang (http://crbug.com/96315)." - echo "Disable it in Preferences->Building (lower right), or run" - echo " defaults write ${XCONF} EnablePredictiveCompilation -boolean NO" - echo "while Xcode is not running." - echo - fi - - SUB_VERSION=$(xcodebuild -version | sed -Ene 's/Xcode 3\.2\.([0-9]+)/\1/p') - if [[ "${SUB_VERSION}" < 6 ]]; then - echo - echo " YOUR LD IS BUGGY!" - echo "Please upgrade Xcode to at least 3.2.6." - echo - fi -fi - -echo Getting LLVM r"${CLANG_RELEASE}" in "${LLVM_DIR}" -if ! svn co --force \ - "${LLVM_REPO_URL}/llvm/branches/release_${CLANG_RELEASE/./}" \ - "${LLVM_DIR}"; then - echo Checkout failed, retrying - rm -rf "${LLVM_DIR}" - svn co --force \ - "${LLVM_REPO_URL}/llvm/branches/release_${CLANG_RELEASE/./}" \ - "${LLVM_DIR}" -fi - -echo Getting clang r"${CLANG_RELEASE}" in "${CLANG_DIR}" -svn co --force \ - "${LLVM_REPO_URL}/cfe/branches/release_${CLANG_RELEASE/./}" \ - "${CLANG_DIR}" - -# Echo all commands -set -x - -NUM_JOBS=3 -if [[ "${OS}" = "Linux" ]]; then - NUM_JOBS="$(grep -c "^processor" /proc/cpuinfo)" -elif [ "${OS}" = "Darwin" ]; then - NUM_JOBS="$(sysctl -n hw.ncpu)" -fi - -# Build clang. -cd "${LLVM_DIR}" -if [[ ! -f ./config.status ]]; then - ../llvm/configure \ - --enable-optimized \ - --disable-threads \ - --disable-pthreads \ - --without-llvmgcc \ - --without-llvmgxx -fi - -MACOSX_DEPLOYMENT_TARGET=10.5 make -j"${NUM_JOBS}" -STRIP_FLAGS= -if [ "${OS}" = "Darwin" ]; then - # See http://crbug.com/256342 - STRIP_FLAGS=-x -fi -strip ${STRIP_FLAGS} Release/bin/clang -cd - - -# Build libgcmole.so -make -C "${THIS_DIR}" clean -make -C "${THIS_DIR}" LLVM_SRC_ROOT="${LLVM_DIR}" libgcmole.so - -set +x - -echo -echo You can now run gcmole using this command: -echo -echo CLANG_BIN=\"third_party/llvm/Release/bin\" lua tools/gcmole/gcmole.lua -echo diff --git a/chromium/v8/tools/gcmole/gcmole.lua b/chromium/v8/tools/gcmole/gcmole.lua index aa9324756ac..66aff942a49 100644 --- a/chromium/v8/tools/gcmole/gcmole.lua +++ b/chromium/v8/tools/gcmole/gcmole.lua @@ -103,10 +103,7 @@ local function MakeClangCommandLine(plugin, plugin_args, triple, arch_define) .. " -triple " .. triple .. " -D" .. arch_define .. " -DENABLE_DEBUGGER_SUPPORT" - .. " -DV8_I18N_SUPPORT" .. " -Isrc" - .. " -Ithird_party/icu/source/common" - .. " -Ithird_party/icu/source/i18n" end function InvokeClangPluginForEachFile(filenames, cfg, func) diff --git a/chromium/v8/tools/grokdump.py b/chromium/v8/tools/grokdump.py index 12ccefdef74..9719376d7f4 100755 --- a/chromium/v8/tools/grokdump.py +++ b/chromium/v8/tools/grokdump.py @@ -40,7 +40,6 @@ import re import struct import sys import types -import v8heapconst USAGE="""usage: %prog [OPTIONS] [DUMP-FILE] @@ -164,11 +163,6 @@ def FullDump(reader, heap): reader.ForEachMemoryRegion(dump_region) -# Heap constants generated by 'make grokdump' in v8heapconst module. -INSTANCE_TYPES = v8heapconst.INSTANCE_TYPES -KNOWN_MAPS = v8heapconst.KNOWN_MAPS -KNOWN_OBJECTS = v8heapconst.KNOWN_OBJECTS - # Set of structures and constants that describe the layout of minidump # files. Based on MSDN and Google Breakpad. @@ -760,14 +754,6 @@ class MinidumpReader(object): elif self.arch == MD_CPU_ARCHITECTURE_X86: return self.exception_context.esp - def ExceptionFP(self): - if self.arch == MD_CPU_ARCHITECTURE_AMD64: - return self.exception_context.rbp - elif self.arch == MD_CPU_ARCHITECTURE_ARM: - return None - elif self.arch == MD_CPU_ARCHITECTURE_X86: - return self.exception_context.ebp - def FormatIntPtr(self, value): if self.arch == MD_CPU_ARCHITECTURE_AMD64: return "%016x" % value @@ -848,6 +834,262 @@ class MinidumpReader(object): return "%s+0x%x" % (symbol.name, diff) + +# List of V8 instance types. Obtained by adding the code below to any .cc file. +# +# #define DUMP_TYPE(T) printf(" %d: \"%s\",\n", T, #T); +# struct P { +# P() { +# printf("INSTANCE_TYPES = {\n"); +# INSTANCE_TYPE_LIST(DUMP_TYPE) +# printf("}\n"); +# } +# }; +# static P p; +INSTANCE_TYPES = { + 0: "STRING_TYPE", + 4: "ASCII_STRING_TYPE", + 1: "CONS_STRING_TYPE", + 5: "CONS_ASCII_STRING_TYPE", + 3: "SLICED_STRING_TYPE", + 2: "EXTERNAL_STRING_TYPE", + 6: "EXTERNAL_ASCII_STRING_TYPE", + 10: "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE", + 18: "SHORT_EXTERNAL_STRING_TYPE", + 22: "SHORT_EXTERNAL_ASCII_STRING_TYPE", + 26: "SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE", + 64: "INTERNALIZED_STRING_TYPE", + 68: "ASCII_INTERNALIZED_STRING_TYPE", + 65: "CONS_INTERNALIZED_STRING_TYPE", + 69: "CONS_ASCII_INTERNALIZED_STRING_TYPE", + 66: "EXTERNAL_INTERNALIZED_STRING_TYPE", + 70: "EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE", + 74: "EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE", + 82: "SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE", + 86: "SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE", + 90: "SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE", + 128: "SYMBOL_TYPE", + 129: "MAP_TYPE", + 130: "CODE_TYPE", + 131: "ODDBALL_TYPE", + 132: "JS_GLOBAL_PROPERTY_CELL_TYPE", + 133: "HEAP_NUMBER_TYPE", + 134: "FOREIGN_TYPE", + 135: "BYTE_ARRAY_TYPE", + 136: "FREE_SPACE_TYPE", + 137: "EXTERNAL_BYTE_ARRAY_TYPE", + 138: "EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE", + 139: "EXTERNAL_SHORT_ARRAY_TYPE", + 140: "EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE", + 141: "EXTERNAL_INT_ARRAY_TYPE", + 142: "EXTERNAL_UNSIGNED_INT_ARRAY_TYPE", + 143: "EXTERNAL_FLOAT_ARRAY_TYPE", + 145: "EXTERNAL_PIXEL_ARRAY_TYPE", + 147: "FILLER_TYPE", + 148: "DECLARED_ACCESSOR_DESCRIPTOR_TYPE", + 149: "DECLARED_ACCESSOR_INFO_TYPE", + 150: "EXECUTABLE_ACCESSOR_INFO_TYPE", + 151: "ACCESSOR_PAIR_TYPE", + 152: "ACCESS_CHECK_INFO_TYPE", + 153: "INTERCEPTOR_INFO_TYPE", + 154: "CALL_HANDLER_INFO_TYPE", + 155: "FUNCTION_TEMPLATE_INFO_TYPE", + 156: "OBJECT_TEMPLATE_INFO_TYPE", + 157: "SIGNATURE_INFO_TYPE", + 158: "TYPE_SWITCH_INFO_TYPE", + 159: "ALLOCATION_SITE_INFO_TYPE", + 160: "SCRIPT_TYPE", + 161: "CODE_CACHE_TYPE", + 162: "POLYMORPHIC_CODE_CACHE_TYPE", + 163: "TYPE_FEEDBACK_INFO_TYPE", + 164: "ALIASED_ARGUMENTS_ENTRY_TYPE", + 167: "FIXED_ARRAY_TYPE", + 146: "FIXED_DOUBLE_ARRAY_TYPE", + 168: "SHARED_FUNCTION_INFO_TYPE", + 169: "JS_MESSAGE_OBJECT_TYPE", + 172: "JS_VALUE_TYPE", + 173: "JS_DATE_TYPE", + 174: "JS_OBJECT_TYPE", + 175: "JS_CONTEXT_EXTENSION_OBJECT_TYPE", + 176: "JS_MODULE_TYPE", + 177: "JS_GLOBAL_OBJECT_TYPE", + 178: "JS_BUILTINS_OBJECT_TYPE", + 179: "JS_GLOBAL_PROXY_TYPE", + 180: "JS_ARRAY_TYPE", + 171: "JS_PROXY_TYPE", + 183: "JS_WEAK_MAP_TYPE", + 184: "JS_WEAK_SET_TYPE", + 185: "JS_REGEXP_TYPE", + 186: "JS_FUNCTION_TYPE", + 170: "JS_FUNCTION_PROXY_TYPE", + 165: "DEBUG_INFO_TYPE", + 166: "BREAK_POINT_INFO_TYPE", +} + + +# List of known V8 maps. Used to determine the instance type and name +# for maps that are part of the root-set and hence on the first page of +# the map-space. Obtained by adding the code below to an IA32 release +# build with enabled snapshots to the end of the Isolate::Init method. +# +# #define ROOT_LIST_CASE(type, name, camel_name) \ +# if (o == heap_.name()) n = #camel_name; +# #define STRUCT_LIST_CASE(upper_name, camel_name, name) \ +# if (o == heap_.name##_map()) n = #camel_name "Map"; +# HeapObjectIterator it(heap_.map_space()); +# printf("KNOWN_MAPS = {\n"); +# for (Object* o = it.Next(); o != NULL; o = it.Next()) { +# Map* m = Map::cast(o); +# const char* n = ""; +# intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff; +# int t = m->instance_type(); +# ROOT_LIST(ROOT_LIST_CASE) +# STRUCT_LIST(STRUCT_LIST_CASE) +# printf(" 0x%05x: (%d, \"%s\"),\n", p, t, n); +# } +# printf("}\n"); +KNOWN_MAPS = { + 0x08081: (135, "ByteArrayMap"), + 0x080a9: (129, "MetaMap"), + 0x080d1: (131, "OddballMap"), + 0x080f9: (68, "AsciiInternalizedStringMap"), + 0x08121: (167, "FixedArrayMap"), + 0x08149: (133, "HeapNumberMap"), + 0x08171: (136, "FreeSpaceMap"), + 0x08199: (147, "OnePointerFillerMap"), + 0x081c1: (147, "TwoPointerFillerMap"), + 0x081e9: (132, "GlobalPropertyCellMap"), + 0x08211: (168, "SharedFunctionInfoMap"), + 0x08239: (167, "NativeContextMap"), + 0x08261: (130, "CodeMap"), + 0x08289: (167, "ScopeInfoMap"), + 0x082b1: (167, "FixedCOWArrayMap"), + 0x082d9: (146, "FixedDoubleArrayMap"), + 0x08301: (167, "HashTableMap"), + 0x08329: (128, "SymbolMap"), + 0x08351: (0, "StringMap"), + 0x08379: (4, "AsciiStringMap"), + 0x083a1: (1, "ConsStringMap"), + 0x083c9: (5, "ConsAsciiStringMap"), + 0x083f1: (3, "SlicedStringMap"), + 0x08419: (7, "SlicedAsciiStringMap"), + 0x08441: (2, "ExternalStringMap"), + 0x08469: (10, "ExternalStringWithAsciiDataMap"), + 0x08491: (6, "ExternalAsciiStringMap"), + 0x084b9: (18, "ShortExternalStringMap"), + 0x084e1: (26, "ShortExternalStringWithAsciiDataMap"), + 0x08509: (64, "InternalizedStringMap"), + 0x08531: (65, "ConsInternalizedStringMap"), + 0x08559: (69, "ConsAsciiInternalizedStringMap"), + 0x08581: (66, "ExternalInternalizedStringMap"), + 0x085a9: (74, "ExternalInternalizedStringWithAsciiDataMap"), + 0x085d1: (70, "ExternalAsciiInternalizedStringMap"), + 0x085f9: (82, "ShortExternalInternalizedStringMap"), + 0x08621: (90, "ShortExternalInternalizedStringWithAsciiDataMap"), + 0x08649: (86, "ShortExternalAsciiInternalizedStringMap"), + 0x08671: (22, "ShortExternalAsciiStringMap"), + 0x08699: (0, "UndetectableStringMap"), + 0x086c1: (4, "UndetectableAsciiStringMap"), + 0x086e9: (145, "ExternalPixelArrayMap"), + 0x08711: (137, "ExternalByteArrayMap"), + 0x08739: (138, "ExternalUnsignedByteArrayMap"), + 0x08761: (139, "ExternalShortArrayMap"), + 0x08789: (140, "ExternalUnsignedShortArrayMap"), + 0x087b1: (141, "ExternalIntArrayMap"), + 0x087d9: (142, "ExternalUnsignedIntArrayMap"), + 0x08801: (143, "ExternalFloatArrayMap"), + 0x08829: (144, "ExternalDoubleArrayMap"), + 0x08851: (167, "NonStrictArgumentsElementsMap"), + 0x08879: (167, "FunctionContextMap"), + 0x088a1: (167, "CatchContextMap"), + 0x088c9: (167, "WithContextMap"), + 0x088f1: (167, "BlockContextMap"), + 0x08919: (167, "ModuleContextMap"), + 0x08941: (167, "GlobalContextMap"), + 0x08969: (169, "JSMessageObjectMap"), + 0x08991: (134, "ForeignMap"), + 0x089b9: (174, "NeanderMap"), + 0x089e1: (159, "AllocationSiteInfoMap"), + 0x08a09: (162, "PolymorphicCodeCacheMap"), + 0x08a31: (160, "ScriptMap"), + 0x08a59: (174, ""), + 0x08a81: (174, "ExternalMap"), + 0x08aa9: (148, "DeclaredAccessorDescriptorMap"), + 0x08ad1: (149, "DeclaredAccessorInfoMap"), + 0x08af9: (150, "ExecutableAccessorInfoMap"), + 0x08b21: (151, "AccessorPairMap"), + 0x08b49: (152, "AccessCheckInfoMap"), + 0x08b71: (153, "InterceptorInfoMap"), + 0x08b99: (154, "CallHandlerInfoMap"), + 0x08bc1: (155, "FunctionTemplateInfoMap"), + 0x08be9: (156, "ObjectTemplateInfoMap"), + 0x08c11: (157, "SignatureInfoMap"), + 0x08c39: (158, "TypeSwitchInfoMap"), + 0x08c61: (161, "CodeCacheMap"), + 0x08c89: (163, "TypeFeedbackInfoMap"), + 0x08cb1: (164, "AliasedArgumentsEntryMap"), + 0x08cd9: (165, "DebugInfoMap"), + 0x08d01: (166, "BreakPointInfoMap"), +} + + +# List of known V8 objects. Used to determine name for objects that are +# part of the root-set and hence on the first page of various old-space +# paged. Obtained by adding the code below to an IA32 release build with +# enabled snapshots to the end of the Isolate::Init method. +# +# #define ROOT_LIST_CASE(type, name, camel_name) \ +# if (o == heap_.name()) n = #camel_name; +# OldSpaces spit(heap()); +# printf("KNOWN_OBJECTS = {\n"); +# for (PagedSpace* s = spit.next(); s != NULL; s = spit.next()) { +# HeapObjectIterator it(s); +# const char* sname = AllocationSpaceName(s->identity()); +# for (Object* o = it.Next(); o != NULL; o = it.Next()) { +# const char* n = NULL; +# intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff; +# ROOT_LIST(ROOT_LIST_CASE) +# if (n != NULL) { +# printf(" (\"%s\", 0x%05x): \"%s\",\n", sname, p, n); +# } +# } +# } +# printf("}\n"); +KNOWN_OBJECTS = { + ("OLD_POINTER_SPACE", 0x08081): "NullValue", + ("OLD_POINTER_SPACE", 0x08091): "UndefinedValue", + ("OLD_POINTER_SPACE", 0x080a1): "InstanceofCacheMap", + ("OLD_POINTER_SPACE", 0x080b1): "TrueValue", + ("OLD_POINTER_SPACE", 0x080c1): "FalseValue", + ("OLD_POINTER_SPACE", 0x080d1): "NoInterceptorResultSentinel", + ("OLD_POINTER_SPACE", 0x080e1): "ArgumentsMarker", + ("OLD_POINTER_SPACE", 0x080f1): "NumberStringCache", + ("OLD_POINTER_SPACE", 0x088f9): "SingleCharacterStringCache", + ("OLD_POINTER_SPACE", 0x08b01): "StringSplitCache", + ("OLD_POINTER_SPACE", 0x08f09): "RegExpMultipleCache", + ("OLD_POINTER_SPACE", 0x09311): "TerminationException", + ("OLD_POINTER_SPACE", 0x09321): "MessageListeners", + ("OLD_POINTER_SPACE", 0x0933d): "CodeStubs", + ("OLD_POINTER_SPACE", 0x09fa5): "NonMonomorphicCache", + ("OLD_POINTER_SPACE", 0x0a5b9): "PolymorphicCodeCache", + ("OLD_POINTER_SPACE", 0x0a5c1): "NativesSourceCache", + ("OLD_POINTER_SPACE", 0x0a601): "EmptyScript", + ("OLD_POINTER_SPACE", 0x0a63d): "IntrinsicFunctionNames", + ("OLD_POINTER_SPACE", 0x0d659): "ObservationState", + ("OLD_POINTER_SPACE", 0x27415): "SymbolTable", + ("OLD_DATA_SPACE", 0x08099): "EmptyDescriptorArray", + ("OLD_DATA_SPACE", 0x080a1): "EmptyFixedArray", + ("OLD_DATA_SPACE", 0x080a9): "NanValue", + ("OLD_DATA_SPACE", 0x08125): "EmptyByteArray", + ("OLD_DATA_SPACE", 0x0812d): "EmptyString", + ("OLD_DATA_SPACE", 0x08259): "InfinityValue", + ("OLD_DATA_SPACE", 0x08265): "MinusZeroValue", + ("OLD_DATA_SPACE", 0x08271): "PrototypeAccessors", + ("CODE_SPACE", 0x0aea1): "JsEntryCode", + ("CODE_SPACE", 0x0b5c1): "JsConstructEntryCode", +} + + class Printer(object): """Printer with indentation support.""" @@ -1959,15 +2201,11 @@ def AnalyzeMinidump(options, minidump_name): print "Kthxbye." elif not options.command: if reader.exception is not None: - frame_pointer = reader.ExceptionFP() print "Annotated stack (from exception.esp to bottom):" for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): maybe_address = reader.ReadUIntPtr(slot) heap_object = heap.FindObject(maybe_address) maybe_symbol = reader.FindSymbol(maybe_address) - if slot == frame_pointer: - maybe_symbol = "<---- frame pointer" - frame_pointer = maybe_address print "%s: %s %s" % (reader.FormatIntPtr(slot), reader.FormatIntPtr(maybe_address), maybe_symbol or "") diff --git a/chromium/v8/tools/gyp/v8.gyp b/chromium/v8/tools/gyp/v8.gyp index 66376c17df5..bdbc7163df4 100644 --- a/chromium/v8/tools/gyp/v8.gyp +++ b/chromium/v8/tools/gyp/v8.gyp @@ -290,7 +290,6 @@ '../../src/double.h', '../../src/dtoa.cc', '../../src/dtoa.h', - '../../src/effects.h', '../../src/elements-kind.cc', '../../src/elements-kind.h', '../../src/elements.cc', @@ -823,14 +822,20 @@ }], ['v8_enable_i18n_support==1', { 'sources': [ - '../../src/i18n.cc', - '../../src/i18n.h', '../../src/extensions/i18n/break-iterator.cc', '../../src/extensions/i18n/break-iterator.h', + '../../src/extensions/i18n/collator.cc', + '../../src/extensions/i18n/collator.h', + '../../src/extensions/i18n/date-format.cc', + '../../src/extensions/i18n/date-format.h', '../../src/extensions/i18n/i18n-extension.cc', '../../src/extensions/i18n/i18n-extension.h', '../../src/extensions/i18n/i18n-utils.cc', '../../src/extensions/i18n/i18n-utils.h', + '../../src/extensions/i18n/locale.cc', + '../../src/extensions/i18n/locale.h', + '../../src/extensions/i18n/number-format.cc', + '../../src/extensions/i18n/number-format.h', ], 'dependencies': [ '<(DEPTH)/third_party/icu/icu.gyp:icui18n', @@ -902,8 +907,7 @@ '../../src/typedarray.js', '../../src/generator.js', '../../src/array-iterator.js', - '../../src/harmony-string.js', - '../../src/harmony-array.js', + '../../src/harmony-string.js' ], 'i18n_library_files': [ '../../src/extensions/i18n/header.js', diff --git a/chromium/v8/tools/run-tests.py b/chromium/v8/tools/run-tests.py index 48682d4444e..761d03fe335 100755 --- a/chromium/v8/tools/run-tests.py +++ b/chromium/v8/tools/run-tests.py @@ -94,9 +94,6 @@ def BuildOptions(): default=False, action="store_true") result.add_option("--cat", help="Print the source of the tests", default=False, action="store_true") - result.add_option("--flaky-tests", - help="Regard tests marked as flaky (run|skip|dontcare)", - default="dontcare") result.add_option("--command-prefix", help="Prepended to each shell command used to run a test", default="") @@ -207,9 +204,6 @@ def ProcessOptions(options): # This is OK for distributed running, so we don't need to set no_network. options.command_prefix = (["python", "-u", run_valgrind] + options.command_prefix) - if not options.flaky_tests in ["run", "skip", "dontcare"]: - print "Unknown flaky test mode %s" % options.flaky_tests - return False return True @@ -321,7 +315,7 @@ def Execute(arch, mode, args, options, suites, workspace): if len(args) > 0: s.FilterTestCasesByArgs(args) all_tests += s.tests - s.FilterTestCasesByStatus(options.warn_unused, options.flaky_tests) + s.FilterTestCasesByStatus(options.warn_unused) if options.cat: verbose.PrintTestSource(s.tests) continue diff --git a/chromium/v8/tools/testrunner/local/old_statusfile.py b/chromium/v8/tools/testrunner/local/old_statusfile.py index d634e3ec955..a9a62036ec4 100644 --- a/chromium/v8/tools/testrunner/local/old_statusfile.py +++ b/chromium/v8/tools/testrunner/local/old_statusfile.py @@ -37,7 +37,6 @@ OKAY = 'OKAY' TIMEOUT = 'TIMEOUT' CRASH = 'CRASH' SLOW = 'SLOW' -FLAKY = 'FLAKY' # These are just for the status files and are mapped below in DEFS: FAIL_OK = 'FAIL_OK' PASS_OR_FAIL = 'PASS_OR_FAIL' @@ -49,7 +48,6 @@ KEYWORDS = {SKIP: SKIP, TIMEOUT: TIMEOUT, CRASH: CRASH, SLOW: SLOW, - FLAKY: FLAKY, FAIL_OK: FAIL_OK, PASS_OR_FAIL: PASS_OR_FAIL} diff --git a/chromium/v8/tools/testrunner/local/statusfile.py b/chromium/v8/tools/testrunner/local/statusfile.py index 1d30fe3d3c1..634fe6a08a8 100644 --- a/chromium/v8/tools/testrunner/local/statusfile.py +++ b/chromium/v8/tools/testrunner/local/statusfile.py @@ -42,7 +42,6 @@ OKAY = "OKAY" TIMEOUT = "TIMEOUT" CRASH = "CRASH" SLOW = "SLOW" -FLAKY = "FLAKY" # These are just for the status files and are mapped below in DEFS: FAIL_OK = "FAIL_OK" PASS_OR_FAIL = "PASS_OR_FAIL" @@ -50,7 +49,7 @@ PASS_OR_FAIL = "PASS_OR_FAIL" ALWAYS = "ALWAYS" KEYWORDS = {} -for key in [SKIP, FAIL, PASS, OKAY, TIMEOUT, CRASH, SLOW, FLAKY, FAIL_OK, +for key in [SKIP, FAIL, PASS, OKAY, TIMEOUT, CRASH, SLOW, FAIL_OK, PASS_OR_FAIL, ALWAYS]: KEYWORDS[key] = key @@ -69,10 +68,6 @@ def DoSkip(outcomes): def IsFlaky(outcomes): - return FLAKY in outcomes - - -def IsPassOrFail(outcomes): return ((PASS in outcomes) and (FAIL in outcomes) and (not CRASH in outcomes) and (not OKAY in outcomes)) diff --git a/chromium/v8/tools/testrunner/local/testsuite.py b/chromium/v8/tools/testrunner/local/testsuite.py index b0372e7f739..473e8b1efed 100644 --- a/chromium/v8/tools/testrunner/local/testsuite.py +++ b/chromium/v8/tools/testrunner/local/testsuite.py @@ -66,10 +66,7 @@ class TestSuite(object): # Used in the status file and for stdout printing. def CommonTestName(self, testcase): - if utils.IsWindows(): - return testcase.path.replace("\\", "/") - else: - return testcase.path + return testcase.path def ListTests(self, context): raise NotImplementedError @@ -87,36 +84,32 @@ class TestSuite(object): def ReadTestCases(self, context): self.tests = self.ListTests(context) - @staticmethod - def _FilterFlaky(flaky, mode): - return (mode == "run" and not flaky) or (mode == "skip" and flaky) - - def FilterTestCasesByStatus(self, warn_unused_rules, flaky_tests="dontcare"): + def FilterTestCasesByStatus(self, warn_unused_rules): filtered = [] used_rules = set() for t in self.tests: - flaky = False testname = self.CommonTestName(t) + if utils.IsWindows(): + testname = testname.replace("\\", "/") if testname in self.rules: used_rules.add(testname) - # Even for skipped tests, as the TestCase object stays around and - # PrintReport() uses it. - t.outcomes = self.rules[testname] - if statusfile.DoSkip(t.outcomes): + outcomes = self.rules[testname] + t.outcomes = outcomes # Even for skipped tests, as the TestCase + # object stays around and PrintReport() uses it. + if statusfile.DoSkip(outcomes): continue # Don't add skipped tests to |filtered|. - flaky = statusfile.IsFlaky(t.outcomes) - skip = False - for rule in self.wildcards: - assert rule[-1] == '*' - if testname.startswith(rule[:-1]): - used_rules.add(rule) - t.outcomes = self.wildcards[rule] - if statusfile.DoSkip(t.outcomes): - skip = True - break # "for rule in self.wildcards" - flaky = flaky or statusfile.IsFlaky(t.outcomes) - if skip or self._FilterFlaky(flaky, flaky_tests): - continue # "for t in self.tests" + if len(self.wildcards) != 0: + skip = False + for rule in self.wildcards: + assert rule[-1] == '*' + if testname.startswith(rule[:-1]): + used_rules.add(rule) + outcomes = self.wildcards[rule] + t.outcomes = outcomes + if statusfile.DoSkip(outcomes): + skip = True + break # "for rule in self.wildcards" + if skip: continue # "for t in self.tests" filtered.append(t) self.tests = filtered diff --git a/chromium/v8/tools/testrunner/local/verbose.py b/chromium/v8/tools/testrunner/local/verbose.py index 00c330d2d9c..f6934675231 100644 --- a/chromium/v8/tools/testrunner/local/verbose.py +++ b/chromium/v8/tools/testrunner/local/verbose.py @@ -54,7 +54,7 @@ def PrintReport(tests): skipped += 1 continue if statusfile.TIMEOUT in o: timeout += 1 - if statusfile.IsPassOrFail(o): nocrash += 1 + if statusfile.IsFlaky(o): nocrash += 1 if list(o) == [statusfile.PASS]: passes += 1 if statusfile.IsFailOk(o): fail_ok += 1 if list(o) == [statusfile.FAIL]: fail += 1 diff --git a/chromium/v8/tools/tickprocessor.js b/chromium/v8/tools/tickprocessor.js index f1a11ccc948..967bd3c5b71 100644 --- a/chromium/v8/tools/tickprocessor.js +++ b/chromium/v8/tools/tickprocessor.js @@ -249,8 +249,7 @@ TickProcessor.VmStates = { GC: 1, COMPILER: 2, OTHER: 3, - EXTERNAL: 4, - IDLE: 5 + EXTERNAL: 4 }; diff --git a/chromium/v8/tools/v8heapconst.py b/chromium/v8/tools/v8heapconst.py deleted file mode 100644 index 57a1f595ace..00000000000 --- a/chromium/v8/tools/v8heapconst.py +++ /dev/null @@ -1,255 +0,0 @@ -# Copyright 2013 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. - -# This file is automatically generated from the V8 source and should not -# be modified manually, run 'make grokdump' instead to update this file. - -# List of known V8 instance types. -INSTANCE_TYPES = { - 64: "STRING_TYPE", - 68: "ASCII_STRING_TYPE", - 65: "CONS_STRING_TYPE", - 69: "CONS_ASCII_STRING_TYPE", - 67: "SLICED_STRING_TYPE", - 71: "SLICED_ASCII_STRING_TYPE", - 66: "EXTERNAL_STRING_TYPE", - 70: "EXTERNAL_ASCII_STRING_TYPE", - 74: "EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE", - 82: "SHORT_EXTERNAL_STRING_TYPE", - 86: "SHORT_EXTERNAL_ASCII_STRING_TYPE", - 90: "SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE", - 0: "INTERNALIZED_STRING_TYPE", - 4: "ASCII_INTERNALIZED_STRING_TYPE", - 1: "CONS_INTERNALIZED_STRING_TYPE", - 5: "CONS_ASCII_INTERNALIZED_STRING_TYPE", - 2: "EXTERNAL_INTERNALIZED_STRING_TYPE", - 6: "EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE", - 10: "EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE", - 18: "SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE", - 22: "SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE", - 26: "SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE", - 128: "SYMBOL_TYPE", - 129: "MAP_TYPE", - 130: "CODE_TYPE", - 131: "ODDBALL_TYPE", - 132: "CELL_TYPE", - 133: "PROPERTY_CELL_TYPE", - 134: "HEAP_NUMBER_TYPE", - 135: "FOREIGN_TYPE", - 136: "BYTE_ARRAY_TYPE", - 137: "FREE_SPACE_TYPE", - 138: "EXTERNAL_BYTE_ARRAY_TYPE", - 139: "EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE", - 140: "EXTERNAL_SHORT_ARRAY_TYPE", - 141: "EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE", - 142: "EXTERNAL_INT_ARRAY_TYPE", - 143: "EXTERNAL_UNSIGNED_INT_ARRAY_TYPE", - 144: "EXTERNAL_FLOAT_ARRAY_TYPE", - 145: "EXTERNAL_DOUBLE_ARRAY_TYPE", - 146: "EXTERNAL_PIXEL_ARRAY_TYPE", - 148: "FILLER_TYPE", - 149: "DECLARED_ACCESSOR_DESCRIPTOR_TYPE", - 150: "DECLARED_ACCESSOR_INFO_TYPE", - 151: "EXECUTABLE_ACCESSOR_INFO_TYPE", - 152: "ACCESSOR_PAIR_TYPE", - 153: "ACCESS_CHECK_INFO_TYPE", - 154: "INTERCEPTOR_INFO_TYPE", - 155: "CALL_HANDLER_INFO_TYPE", - 156: "FUNCTION_TEMPLATE_INFO_TYPE", - 157: "OBJECT_TEMPLATE_INFO_TYPE", - 158: "SIGNATURE_INFO_TYPE", - 159: "TYPE_SWITCH_INFO_TYPE", - 161: "ALLOCATION_MEMENTO_TYPE", - 160: "ALLOCATION_SITE_TYPE", - 162: "SCRIPT_TYPE", - 163: "CODE_CACHE_TYPE", - 164: "POLYMORPHIC_CODE_CACHE_TYPE", - 165: "TYPE_FEEDBACK_INFO_TYPE", - 166: "ALIASED_ARGUMENTS_ENTRY_TYPE", - 167: "BOX_TYPE", - 170: "FIXED_ARRAY_TYPE", - 147: "FIXED_DOUBLE_ARRAY_TYPE", - 171: "SHARED_FUNCTION_INFO_TYPE", - 172: "JS_MESSAGE_OBJECT_TYPE", - 175: "JS_VALUE_TYPE", - 176: "JS_DATE_TYPE", - 177: "JS_OBJECT_TYPE", - 178: "JS_CONTEXT_EXTENSION_OBJECT_TYPE", - 179: "JS_GENERATOR_OBJECT_TYPE", - 180: "JS_MODULE_TYPE", - 181: "JS_GLOBAL_OBJECT_TYPE", - 182: "JS_BUILTINS_OBJECT_TYPE", - 183: "JS_GLOBAL_PROXY_TYPE", - 184: "JS_ARRAY_TYPE", - 185: "JS_ARRAY_BUFFER_TYPE", - 186: "JS_TYPED_ARRAY_TYPE", - 187: "JS_DATA_VIEW_TYPE", - 174: "JS_PROXY_TYPE", - 188: "JS_SET_TYPE", - 189: "JS_MAP_TYPE", - 190: "JS_WEAK_MAP_TYPE", - 191: "JS_WEAK_SET_TYPE", - 192: "JS_REGEXP_TYPE", - 193: "JS_FUNCTION_TYPE", - 173: "JS_FUNCTION_PROXY_TYPE", - 168: "DEBUG_INFO_TYPE", - 169: "BREAK_POINT_INFO_TYPE", -} - -# List of known V8 maps. -KNOWN_MAPS = { - 0x08081: (136, "ByteArrayMap"), - 0x080a9: (129, "MetaMap"), - 0x080d1: (131, "OddballMap"), - 0x080f9: (4, "AsciiInternalizedStringMap"), - 0x08121: (170, "FixedArrayMap"), - 0x08149: (134, "HeapNumberMap"), - 0x08171: (137, "FreeSpaceMap"), - 0x08199: (148, "OnePointerFillerMap"), - 0x081c1: (148, "TwoPointerFillerMap"), - 0x081e9: (132, "CellMap"), - 0x08211: (133, "GlobalPropertyCellMap"), - 0x08239: (171, "SharedFunctionInfoMap"), - 0x08261: (170, "NativeContextMap"), - 0x08289: (130, "CodeMap"), - 0x082b1: (170, "ScopeInfoMap"), - 0x082d9: (170, "FixedCOWArrayMap"), - 0x08301: (147, "FixedDoubleArrayMap"), - 0x08329: (170, "HashTableMap"), - 0x08351: (128, "SymbolMap"), - 0x08379: (64, "StringMap"), - 0x083a1: (68, "AsciiStringMap"), - 0x083c9: (65, "ConsStringMap"), - 0x083f1: (69, "ConsAsciiStringMap"), - 0x08419: (67, "SlicedStringMap"), - 0x08441: (71, "SlicedAsciiStringMap"), - 0x08469: (66, "ExternalStringMap"), - 0x08491: (74, "ExternalStringWithOneByteDataMap"), - 0x084b9: (70, "ExternalAsciiStringMap"), - 0x084e1: (82, "ShortExternalStringMap"), - 0x08509: (90, "ShortExternalStringWithOneByteDataMap"), - 0x08531: (0, "InternalizedStringMap"), - 0x08559: (1, "ConsInternalizedStringMap"), - 0x08581: (5, "ConsAsciiInternalizedStringMap"), - 0x085a9: (2, "ExternalInternalizedStringMap"), - 0x085d1: (10, "ExternalInternalizedStringWithOneByteDataMap"), - 0x085f9: (6, "ExternalAsciiInternalizedStringMap"), - 0x08621: (18, "ShortExternalInternalizedStringMap"), - 0x08649: (26, "ShortExternalInternalizedStringWithOneByteDataMap"), - 0x08671: (22, "ShortExternalAsciiInternalizedStringMap"), - 0x08699: (86, "ShortExternalAsciiStringMap"), - 0x086c1: (64, "UndetectableStringMap"), - 0x086e9: (68, "UndetectableAsciiStringMap"), - 0x08711: (138, "ExternalByteArrayMap"), - 0x08739: (139, "ExternalUnsignedByteArrayMap"), - 0x08761: (140, "ExternalShortArrayMap"), - 0x08789: (141, "ExternalUnsignedShortArrayMap"), - 0x087b1: (142, "ExternalIntArrayMap"), - 0x087d9: (143, "ExternalUnsignedIntArrayMap"), - 0x08801: (144, "ExternalFloatArrayMap"), - 0x08829: (145, "ExternalDoubleArrayMap"), - 0x08851: (146, "ExternalPixelArrayMap"), - 0x08879: (170, "NonStrictArgumentsElementsMap"), - 0x088a1: (170, "FunctionContextMap"), - 0x088c9: (170, "CatchContextMap"), - 0x088f1: (170, "WithContextMap"), - 0x08919: (170, "BlockContextMap"), - 0x08941: (170, "ModuleContextMap"), - 0x08969: (170, "GlobalContextMap"), - 0x08991: (172, "JSMessageObjectMap"), - 0x089b9: (135, "ForeignMap"), - 0x089e1: (177, "NeanderMap"), - 0x08a09: (161, "AllocationMementoMap"), - 0x08a31: (160, "AllocationSiteMap"), - 0x08a59: (164, "PolymorphicCodeCacheMap"), - 0x08a81: (162, "ScriptMap"), - 0x08ad1: (177, "ExternalMap"), - 0x08af9: (167, "BoxMap"), - 0x08b21: (149, "DeclaredAccessorDescriptorMap"), - 0x08b49: (150, "DeclaredAccessorInfoMap"), - 0x08b71: (151, "ExecutableAccessorInfoMap"), - 0x08b99: (152, "AccessorPairMap"), - 0x08bc1: (153, "AccessCheckInfoMap"), - 0x08be9: (154, "InterceptorInfoMap"), - 0x08c11: (155, "CallHandlerInfoMap"), - 0x08c39: (156, "FunctionTemplateInfoMap"), - 0x08c61: (157, "ObjectTemplateInfoMap"), - 0x08c89: (158, "SignatureInfoMap"), - 0x08cb1: (159, "TypeSwitchInfoMap"), - 0x08cd9: (163, "CodeCacheMap"), - 0x08d01: (165, "TypeFeedbackInfoMap"), - 0x08d29: (166, "AliasedArgumentsEntryMap"), - 0x08d51: (168, "DebugInfoMap"), - 0x08d79: (169, "BreakPointInfoMap"), -} - -# List of known V8 objects. -KNOWN_OBJECTS = { - ("OLD_POINTER_SPACE", 0x08081): "NullValue", - ("OLD_POINTER_SPACE", 0x08091): "UndefinedValue", - ("OLD_POINTER_SPACE", 0x080a1): "TheHoleValue", - ("OLD_POINTER_SPACE", 0x080b1): "TrueValue", - ("OLD_POINTER_SPACE", 0x080c1): "FalseValue", - ("OLD_POINTER_SPACE", 0x080d1): "UninitializedValue", - ("OLD_POINTER_SPACE", 0x080e1): "NoInterceptorResultSentinel", - ("OLD_POINTER_SPACE", 0x080f1): "ArgumentsMarker", - ("OLD_POINTER_SPACE", 0x08101): "NumberStringCache", - ("OLD_POINTER_SPACE", 0x08909): "SingleCharacterStringCache", - ("OLD_POINTER_SPACE", 0x08d11): "StringSplitCache", - ("OLD_POINTER_SPACE", 0x09119): "RegExpMultipleCache", - ("OLD_POINTER_SPACE", 0x09521): "TerminationException", - ("OLD_POINTER_SPACE", 0x09531): "MessageListeners", - ("OLD_POINTER_SPACE", 0x0954d): "CodeStubs", - ("OLD_POINTER_SPACE", 0x0a9d9): "NonMonomorphicCache", - ("OLD_POINTER_SPACE", 0x0afed): "PolymorphicCodeCache", - ("OLD_POINTER_SPACE", 0x0aff5): "NativesSourceCache", - ("OLD_POINTER_SPACE", 0x0b035): "EmptyScript", - ("OLD_POINTER_SPACE", 0x0b06d): "IntrinsicFunctionNames", - ("OLD_POINTER_SPACE", 0x0e089): "ObservationState", - ("OLD_POINTER_SPACE", 0x0e095): "FrozenSymbol", - ("OLD_POINTER_SPACE", 0x0e0a1): "ElementsTransitionSymbol", - ("OLD_POINTER_SPACE", 0x0e0ad): "EmptySlowElementDictionary", - ("OLD_POINTER_SPACE", 0x0e249): "ObservedSymbol", - ("OLD_POINTER_SPACE", 0x274e9): "StringTable", - ("OLD_DATA_SPACE", 0x08099): "EmptyDescriptorArray", - ("OLD_DATA_SPACE", 0x080a1): "EmptyFixedArray", - ("OLD_DATA_SPACE", 0x080a9): "NanValue", - ("OLD_DATA_SPACE", 0x08141): "EmptyByteArray", - ("OLD_DATA_SPACE", 0x08269): "EmptyExternalByteArray", - ("OLD_DATA_SPACE", 0x08275): "EmptyExternalUnsignedByteArray", - ("OLD_DATA_SPACE", 0x08281): "EmptyExternalShortArray", - ("OLD_DATA_SPACE", 0x0828d): "EmptyExternalUnsignedShortArray", - ("OLD_DATA_SPACE", 0x08299): "EmptyExternalIntArray", - ("OLD_DATA_SPACE", 0x082a5): "EmptyExternalUnsignedIntArray", - ("OLD_DATA_SPACE", 0x082b1): "EmptyExternalFloatArray", - ("OLD_DATA_SPACE", 0x082bd): "EmptyExternalDoubleArray", - ("OLD_DATA_SPACE", 0x082c9): "EmptyExternalPixelArray", - ("OLD_DATA_SPACE", 0x082d5): "InfinityValue", - ("OLD_DATA_SPACE", 0x082e1): "MinusZeroValue", - ("CODE_SPACE", 0x10d01): "JsConstructEntryCode", - ("CODE_SPACE", 0x183c1): "JsEntryCode", -} diff --git a/chromium/v8/tools/v8heapconst.py.tmpl b/chromium/v8/tools/v8heapconst.py.tmpl deleted file mode 100644 index a773f47c8b9..00000000000 --- a/chromium/v8/tools/v8heapconst.py.tmpl +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2013 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. - -# This file is automatically generated from the V8 source and should not -# be modified manually, run 'make grokdump' instead to update this file. - |