diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2013-04-08 20:25:29 +0200 |
---|---|---|
committer | Ben Noordhuis <info@bnoordhuis.nl> | 2013-04-08 20:35:27 +0200 |
commit | 587e83c6d6fa9bba14f5b629fa2ee905dc6881e8 (patch) | |
tree | 49ef341f730dbecbd8a8ea354be0ac35317a30fb /deps | |
parent | 1fd95b57bf51b548651ef7868ce2dd8e65e7cf6f (diff) | |
download | node-587e83c6d6fa9bba14f5b629fa2ee905dc6881e8.tar.gz |
v8: upgrade to 3.17.16
Diffstat (limited to 'deps')
203 files changed, 6256 insertions, 3512 deletions
diff --git a/deps/v8/.gitignore b/deps/v8/.gitignore index 0bf931335..fe8425f02 100644 --- a/deps/v8/.gitignore +++ b/deps/v8/.gitignore @@ -18,6 +18,7 @@ #*# *~ .cpplint-cache +.d8_history d8 d8_g shell @@ -50,3 +51,7 @@ shell_g /xcodebuild TAGS *.Makefile +GTAGS +GRTAGS +GSYMS +GPATH diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index 11c80d717..5bd017fc0 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,43 @@ +2013-04-04: Version 3.17.16 + + Stack trace API: poison stack frames below the first strict mode frame. + (issue 2564) + + Made Isolate::GetHeapStatistics robust against half-initialized + isolates (Chromium issue 2591). + + Finished implementation of ES6 symbols aka. private names (issue 2158). + + Performance and stability improvements on all platforms. + + +2013-03-21: Version 3.17.15 + + Rolled back API changes to maintain compatibility with older + 3.17.x versions of V8. + + Disable zapping of global handles in release mode. + + Always mark the entire valid prefix of the descriptor array. + (Chromium issue 196331) + + Use internal memcpy for CopyWords and when copying code. + (Chromium issue 196330) + + Performance and stability improvements on all platforms. + + +2013-03-20: Version 3.17.14 + + Use internal memcpy when initializing code objects. + (Chromium issue 196330) + + Disabled weak embedded maps because of crashes. + (Chromium issues 172489, 217858) + + Performance and stability improvements on all platforms. + + 2013-03-19: Version 3.17.13 Turned Flags into a uint32_t typedef (Chromium issue 194749). diff --git a/deps/v8/OWNERS b/deps/v8/OWNERS index 941e5fe07..0333d1518 100644 --- a/deps/v8/OWNERS +++ b/deps/v8/OWNERS @@ -1,4 +1,6 @@ danno@chromium.org +dslomov@chromium.org +hpayer@chromium.org jkummerow@chromium.org mmassi@chromium.org mstarzinger@chromium.org diff --git a/deps/v8/build/common.gypi b/deps/v8/build/common.gypi index 38ed4f4c9..a3c9ed094 100644 --- a/deps/v8/build/common.gypi +++ b/deps/v8/build/common.gypi @@ -409,6 +409,15 @@ }], ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" \ or OS=="android"', { + 'cflags!': [ + '-O2', + '-Os', + ], + 'cflags': [ + '-fdata-sections', + '-ffunction-sections', + '-O3', + ], 'conditions': [ [ 'gcc_version==44 and clang==0', { 'cflags': [ diff --git a/deps/v8/include/v8-profiler.h b/deps/v8/include/v8-profiler.h index 41fe8a199..68f377c60 100644 --- a/deps/v8/include/v8-profiler.h +++ b/deps/v8/include/v8-profiler.h @@ -135,7 +135,7 @@ class V8EXPORT CpuProfile { /** * Returns number of samples recorded. The samples are not recorded unless - * |record_samples| parameter of CpuProfiler::StartProfiling is true. + * |record_samples| parameter of CpuProfiler::StartCpuProfiling is true. */ int GetSamplesCount() const; @@ -158,7 +158,8 @@ class V8EXPORT CpuProfile { /** - * Interface for controlling CPU profiling. + * Interface for controlling CPU profiling. Instance of the + * profiler can be retrieved using v8::Isolate::GetCpuProfiler. */ class V8EXPORT CpuProfiler { public: @@ -171,22 +172,34 @@ class V8EXPORT CpuProfiler { * obtaining profiling results. */ + /** Deprecated. Use GetProfileCount instead. */ + static int GetProfilesCount(); /** * Returns the number of profiles collected (doesn't include * profiles that are being collected at the moment of call.) */ - static int GetProfilesCount(); + int GetProfileCount(); - /** Returns a profile by index. */ + /** Deprecated. Use GetCpuProfile instead. */ static const CpuProfile* GetProfile( int index, Handle<Value> security_token = Handle<Value>()); + /** Returns a profile by index. */ + const CpuProfile* GetCpuProfile( + int index, + Handle<Value> security_token = Handle<Value>()); - /** Returns a profile by uid. */ + /** Deprecated. Use FindProfile instead. */ static const CpuProfile* FindProfile( unsigned uid, Handle<Value> security_token = Handle<Value>()); + /** Returns a profile by uid. */ + const CpuProfile* FindCpuProfile( + unsigned uid, + Handle<Value> security_token = Handle<Value>()); + /** Deprecated. Use StartCpuProfiling instead. */ + static void StartProfiling(Handle<String> title, bool record_samples = false); /** * Starts collecting CPU profile. Title may be an empty string. It * is allowed to have several profiles being collected at @@ -198,22 +211,34 @@ class V8EXPORT CpuProfiler { * |record_samples| parameter controls whether individual samples should * be recorded in addition to the aggregated tree. */ - static void StartProfiling(Handle<String> title, bool record_samples = false); + void StartCpuProfiling(Handle<String> title, bool record_samples = false); + /** Deprecated. Use StopCpuProfiling instead. */ + static const CpuProfile* StopProfiling( + Handle<String> title, + Handle<Value> security_token = Handle<Value>()); /** * Stops collecting CPU profile with a given title and returns it. * If the title given is empty, finishes the last profile started. */ - static const CpuProfile* StopProfiling( + const CpuProfile* StopCpuProfiling( Handle<String> title, Handle<Value> security_token = Handle<Value>()); + /** Deprecated. Use DeleteAllCpuProfiles instead. */ + static void DeleteAllProfiles(); /** * Deletes all existing profiles, also cancelling all profiling * activity. All previously returned pointers to profiles and their * contents become invalid after this call. */ - static void DeleteAllProfiles(); + void DeleteAllCpuProfiles(); + + private: + CpuProfiler(); + ~CpuProfiler(); + CpuProfiler(const CpuProfiler&); + CpuProfiler& operator=(const CpuProfiler&); }; @@ -321,8 +346,8 @@ class V8EXPORT HeapSnapshot { kJSON = 0 // See format description near 'Serialize' method. }; - /** Returns heap snapshot type. */ - Type GetType() const; + /** Deprecated. Returns kFull. */ + V8_DEPRECATED(Type GetType() const); /** Returns heap snapshot UID (assigned by the profiler.) */ unsigned GetUid() const; @@ -385,7 +410,8 @@ class V8EXPORT HeapSnapshot { class RetainedObjectInfo; /** - * Interface for controlling heap profiling. + * Interface for controlling heap profiling. Instance of the + * profiler can be retrieved using v8::Isolate::GetHeapProfiler. */ class V8EXPORT HeapProfiler { public: @@ -398,20 +424,28 @@ class V8EXPORT HeapProfiler { typedef RetainedObjectInfo* (*WrapperInfoCallback) (uint16_t class_id, Handle<Value> wrapper); - /** Returns the number of snapshots taken. */ + /** Deprecated. Use GetSnapshotCount instead. */ static int GetSnapshotsCount(); + /** Returns the number of snapshots taken. */ + int GetSnapshotCount(); - /** Returns a snapshot by index. */ + /** Deprecated. Use GetHeapSnapshot instead. */ static const HeapSnapshot* GetSnapshot(int index); + /** Returns a snapshot by index. */ + const HeapSnapshot* GetHeapSnapshot(int index); - /** Returns a profile by uid. */ + /** Deprecated. Use FindHeapSnapshot instead. */ static const HeapSnapshot* FindSnapshot(unsigned uid); + /** Returns a profile by uid. */ + const HeapSnapshot* FindHeapSnapshot(unsigned uid); + /** Deprecated. Use GetObjectId instead. */ + static SnapshotObjectId GetSnapshotObjectId(Handle<Value> value); /** * Returns SnapshotObjectId for a heap object referenced by |value| if * it has been seen by the heap profiler, kUnknownObjectId otherwise. */ - static SnapshotObjectId GetSnapshotObjectId(Handle<Value> value); + SnapshotObjectId GetObjectId(Handle<Value> value); /** * A constant for invalid SnapshotObjectId. GetSnapshotObjectId will return @@ -424,33 +458,42 @@ class V8EXPORT HeapProfiler { * Callback interface for retrieving user friendly names of global objects. */ class ObjectNameResolver { - public: + public: /** * Returns name to be used in the heap snapshot for given node. Returned * string must stay alive until snapshot collection is completed. */ virtual const char* GetName(Handle<Object> object) = 0; - protected: + protected: virtual ~ObjectNameResolver() {} }; + /** Deprecated. Use TakeHeapSnapshot instead. */ + static const HeapSnapshot* TakeSnapshot( + Handle<String> title, + HeapSnapshot::Type type = HeapSnapshot::kFull, + ActivityControl* control = NULL, + ObjectNameResolver* global_object_name_resolver = NULL); /** * Takes a heap snapshot and returns it. Title may be an empty string. - * See HeapSnapshot::Type for types description. */ - static const HeapSnapshot* TakeSnapshot( + const HeapSnapshot* TakeHeapSnapshot( Handle<String> title, - HeapSnapshot::Type type = HeapSnapshot::kFull, ActivityControl* control = NULL, ObjectNameResolver* global_object_name_resolver = NULL); + + /** Deprecated. Use StartTrackingHeapObjects instead. */ + static void StartHeapObjectsTracking(); /** * Starts tracking of heap objects population statistics. After calling * this method, all heap objects relocations done by the garbage collector * are being registered. */ - static void StartHeapObjectsTracking(); + void StartTrackingHeapObjects(); + /** Deprecated. Use GetHeapStats instead. */ + static SnapshotObjectId PushHeapObjectsStats(OutputStream* stream); /** * Adds a new time interval entry to the aggregated statistics array. The * time interval entry contains information on the current heap objects @@ -460,28 +503,36 @@ class V8EXPORT HeapProfiler { * HeapStatsUpdate structure instances. * The return value of the function is the last seen heap object Id. * - * StartHeapObjectsTracking must be called before the first call to this + * StartTrackingHeapObjects must be called before the first call to this * method. */ - static SnapshotObjectId PushHeapObjectsStats(OutputStream* stream); + SnapshotObjectId GetHeapStats(OutputStream* stream); + /** Deprecated. Use StopTrackingHeapObjects instead. */ + static void StopHeapObjectsTracking(); /** * Stops tracking of heap objects population statistics, cleans up all * collected data. StartHeapObjectsTracking must be called again prior to * calling PushHeapObjectsStats next time. */ - static void StopHeapObjectsTracking(); + void StopTrackingHeapObjects(); + /** Deprecated. Use DeleteAllHeapSnapshots instead. */ + static void DeleteAllSnapshots(); /** * Deletes all snapshots taken. All previously returned pointers to * snapshots and their contents become invalid after this call. */ - static void DeleteAllSnapshots(); + void DeleteAllHeapSnapshots(); - /** Binds a callback to embedder's class ID. */ + /** Deprecated. Use SetWrapperClassInfoProvider instead. */ static void DefineWrapperClass( uint16_t class_id, WrapperInfoCallback callback); + /** Binds a callback to embedder's class ID. */ + void SetWrapperClassInfoProvider( + uint16_t class_id, + WrapperInfoCallback callback); /** * Default value of persistent handle class ID. Must not be used to @@ -490,11 +541,21 @@ class V8EXPORT HeapProfiler { */ static const uint16_t kPersistentHandleNoClassId = 0; - /** Returns the number of currently existing persistent handles. */ + /** + * Deprecated. Returns the number of currently existing persistent handles. + */ static int GetPersistentHandleCount(); - /** Returns memory used for profiler internal data and snapshots. */ + /** Deprecated. Use GetHeapProfilerMemorySize instead. */ static size_t GetMemorySizeUsedByProfiler(); + /** Returns memory used for profiler internal data and snapshots. */ + size_t GetProfilerMemorySize(); + + private: + HeapProfiler(); + ~HeapProfiler(); + HeapProfiler(const HeapProfiler&); + HeapProfiler& operator=(const HeapProfiler&); }; @@ -574,7 +635,7 @@ class V8EXPORT RetainedObjectInfo { // NOLINT /** * A struct for exporting HeapStats data from V8, using "push" model. - * See HeapProfiler::PushHeapObjectsStats. + * See HeapProfiler::GetHeapStats. */ struct HeapStatsUpdate { HeapStatsUpdate(uint32_t index, uint32_t count, uint32_t size) diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 329576fa9..9adb1c041 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -103,12 +103,14 @@ class Array; class Boolean; class BooleanObject; class Context; +class CpuProfiler; class Data; class Date; class DeclaredAccessorDescriptor; class External; class Function; class FunctionTemplate; +class HeapProfiler; class ImplementationUtilities; class Int32; class Integer; @@ -3022,6 +3024,18 @@ class V8EXPORT Isolate { */ intptr_t AdjustAmountOfExternalAllocatedMemory(intptr_t change_in_bytes); + /** + * Returns heap profiler for this isolate. Will return NULL until the isolate + * is initialized. + */ + HeapProfiler* GetHeapProfiler(); + + /** + * Returns CPU profiler for this isolate. Will return NULL until the isolate + * is initialized. + */ + CpuProfiler* GetCpuProfiler(); + private: Isolate(); Isolate(const Isolate&); @@ -4274,7 +4288,7 @@ class Internals { static const int kJSObjectHeaderSize = 3 * kApiPointerSize; static const int kFixedArrayHeaderSize = 2 * kApiPointerSize; static const int kContextHeaderSize = 2 * kApiPointerSize; - static const int kContextEmbedderDataIndex = 54; + static const int kContextEmbedderDataIndex = 55; static const int kFullStringRepresentationMask = 0x07; static const int kStringEncodingMask = 0x4; static const int kExternalTwoByteRepresentationTag = 0x02; diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index dfa57654d..65663ba5c 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -477,14 +477,6 @@ void V8::SetAllowCodeGenerationFromStringsCallback( } -#ifdef DEBUG -void ImplementationUtilities::ZapHandleRange(i::Object** begin, - i::Object** end) { - i::HandleScope::ZapRange(begin, end); -} -#endif - - void V8::SetFlagsFromString(const char* str, int length) { i::FlagList::SetFlagsFromString(str, length); } @@ -706,7 +698,7 @@ void HandleScope::Leave() { i::HandleScope::DeleteExtensions(isolate_); } -#ifdef DEBUG +#ifdef ENABLE_EXTRA_CHECKS i::HandleScope::ZapRange(prev_next_, prev_limit_); #endif } @@ -3197,7 +3189,7 @@ Local<String> v8::Object::ObjectProtoToString() { i::Handle<i::Object> name(self->class_name(), isolate); // Native implementation of Object.prototype.toString (v8natives.js): - // var c = %ClassOf(this); + // var c = %_ClassOf(this); // if (c === 'Arguments') c = 'Object'; // return "[object " + c + "]"; @@ -5807,6 +5799,20 @@ intptr_t V8::AdjustAmountOfExternalAllocatedMemory(intptr_t change_in_bytes) { } +HeapProfiler* Isolate::GetHeapProfiler() { + i::HeapProfiler* heap_profiler = + reinterpret_cast<i::Isolate*>(this)->heap_profiler(); + return reinterpret_cast<HeapProfiler*>(heap_profiler); +} + + +CpuProfiler* Isolate::GetCpuProfiler() { + i::CpuProfiler* cpu_profiler = + reinterpret_cast<i::Isolate*>(this)->cpu_profiler(); + return reinterpret_cast<CpuProfiler*>(cpu_profiler); +} + + void V8::SetGlobalGCPrologueCallback(GCCallback callback) { i::Isolate* isolate = i::Isolate::Current(); if (IsDeadCheck(isolate, "v8::V8::SetGlobalGCPrologueCallback()")) return; @@ -5979,6 +5985,14 @@ void Isolate::Exit() { void Isolate::GetHeapStatistics(HeapStatistics* heap_statistics) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); + if (!isolate->IsInitialized()) { + heap_statistics->total_heap_size_ = 0; + heap_statistics->total_heap_size_executable_ = 0; + heap_statistics->total_physical_size_ = 0; + heap_statistics->used_heap_size_ = 0; + heap_statistics->heap_size_limit_ = 0; + return; + } i::Heap* heap = isolate->heap(); heap_statistics->total_heap_size_ = heap->CommittedMemory(); heap_statistics->total_heap_size_executable_ = @@ -6532,6 +6546,11 @@ int CpuProfiler::GetProfilesCount() { } +int CpuProfiler::GetProfileCount() { + return reinterpret_cast<i::CpuProfiler*>(this)->GetProfilesCount(); +} + + const CpuProfile* CpuProfiler::GetProfile(int index, Handle<Value> security_token) { i::Isolate* isolate = i::Isolate::Current(); @@ -6545,6 +6564,15 @@ const CpuProfile* CpuProfiler::GetProfile(int index, } +const CpuProfile* CpuProfiler::GetCpuProfile(int index, + Handle<Value> security_token) { + return reinterpret_cast<const CpuProfile*>( + reinterpret_cast<i::CpuProfiler*>(this)->GetProfile( + security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token), + index)); +} + + const CpuProfile* CpuProfiler::FindProfile(unsigned uid, Handle<Value> security_token) { i::Isolate* isolate = i::Isolate::Current(); @@ -6558,6 +6586,15 @@ const CpuProfile* CpuProfiler::FindProfile(unsigned uid, } +const CpuProfile* CpuProfiler::FindCpuProfile(unsigned uid, + Handle<Value> security_token) { + return reinterpret_cast<const CpuProfile*>( + reinterpret_cast<i::CpuProfiler*>(this)->FindProfile( + security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token), + uid)); +} + + void CpuProfiler::StartProfiling(Handle<String> title, bool record_samples) { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::CpuProfiler::StartProfiling"); @@ -6567,6 +6604,12 @@ void CpuProfiler::StartProfiling(Handle<String> title, bool record_samples) { } +void CpuProfiler::StartCpuProfiling(Handle<String> title, bool record_samples) { + reinterpret_cast<i::CpuProfiler*>(this)->StartProfiling( + *Utils::OpenHandle(*title), record_samples); +} + + const CpuProfile* CpuProfiler::StopProfiling(Handle<String> title, Handle<Value> security_token) { i::Isolate* isolate = i::Isolate::Current(); @@ -6580,6 +6623,15 @@ const CpuProfile* CpuProfiler::StopProfiling(Handle<String> title, } +const CpuProfile* CpuProfiler::StopCpuProfiling(Handle<String> title, + Handle<Value> security_token) { + return reinterpret_cast<const CpuProfile*>( + reinterpret_cast<i::CpuProfiler*>(this)->StopProfiling( + security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token), + *Utils::OpenHandle(*title))); +} + + void CpuProfiler::DeleteAllProfiles() { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::CpuProfiler::DeleteAllProfiles"); @@ -6589,6 +6641,11 @@ void CpuProfiler::DeleteAllProfiles() { } +void CpuProfiler::DeleteAllCpuProfiles() { + reinterpret_cast<i::CpuProfiler*>(this)->DeleteAllProfiles(); +} + + static i::HeapGraphEdge* ToInternal(const HeapGraphEdge* edge) { return const_cast<i::HeapGraphEdge*>( reinterpret_cast<const i::HeapGraphEdge*>(edge)); @@ -6708,11 +6765,11 @@ static i::HeapSnapshot* ToInternal(const HeapSnapshot* snapshot) { void HeapSnapshot::Delete() { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapSnapshot::Delete"); - if (i::HeapProfiler::GetSnapshotsCount() > 1) { + if (isolate->heap_profiler()->GetSnapshotsCount() > 1) { ToInternal(this)->Delete(); } else { // If this is the last snapshot, clean up all accessory data as well. - i::HeapProfiler::DeleteAllSnapshots(); + isolate->heap_profiler()->DeleteAllSnapshots(); } } @@ -6720,7 +6777,7 @@ void HeapSnapshot::Delete() { HeapSnapshot::Type HeapSnapshot::GetType() const { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapSnapshot::GetType"); - return static_cast<HeapSnapshot::Type>(ToInternal(this)->type()); + return kFull; } @@ -6797,7 +6854,12 @@ void HeapSnapshot::Serialize(OutputStream* stream, int HeapProfiler::GetSnapshotsCount() { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapProfiler::GetSnapshotsCount"); - return i::HeapProfiler::GetSnapshotsCount(); + return isolate->heap_profiler()->GetSnapshotsCount(); +} + + +int HeapProfiler::GetSnapshotCount() { + return reinterpret_cast<i::HeapProfiler*>(this)->GetSnapshotsCount(); } @@ -6805,7 +6867,13 @@ const HeapSnapshot* HeapProfiler::GetSnapshot(int index) { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapProfiler::GetSnapshot"); return reinterpret_cast<const HeapSnapshot*>( - i::HeapProfiler::GetSnapshot(index)); + isolate->heap_profiler()->GetSnapshot(index)); +} + + +const HeapSnapshot* HeapProfiler::GetHeapSnapshot(int index) { + return reinterpret_cast<const HeapSnapshot*>( + reinterpret_cast<i::HeapProfiler*>(this)->GetSnapshot(index)); } @@ -6813,7 +6881,13 @@ const HeapSnapshot* HeapProfiler::FindSnapshot(unsigned uid) { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapProfiler::FindSnapshot"); return reinterpret_cast<const HeapSnapshot*>( - i::HeapProfiler::FindSnapshot(uid)); + isolate->heap_profiler()->FindSnapshot(uid)); +} + + +const HeapSnapshot* HeapProfiler::FindHeapSnapshot(unsigned uid) { + return reinterpret_cast<const HeapSnapshot*>( + reinterpret_cast<i::HeapProfiler*>(this)->FindSnapshot(uid)); } @@ -6821,7 +6895,13 @@ SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Value> value) { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapProfiler::GetSnapshotObjectId"); i::Handle<i::Object> obj = Utils::OpenHandle(*value); - return i::HeapProfiler::GetSnapshotObjectId(obj); + return isolate->heap_profiler()->GetSnapshotObjectId(obj); +} + + +SnapshotObjectId HeapProfiler::GetObjectId(Handle<Value> value) { + i::Handle<i::Object> obj = Utils::OpenHandle(*value); + return reinterpret_cast<i::HeapProfiler*>(this)->GetSnapshotObjectId(obj); } @@ -6831,45 +6911,67 @@ const HeapSnapshot* HeapProfiler::TakeSnapshot(Handle<String> title, ObjectNameResolver* resolver) { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapProfiler::TakeSnapshot"); - i::HeapSnapshot::Type internal_type = i::HeapSnapshot::kFull; - switch (type) { - case HeapSnapshot::kFull: - internal_type = i::HeapSnapshot::kFull; - break; - default: - UNREACHABLE(); - } return reinterpret_cast<const HeapSnapshot*>( - i::HeapProfiler::TakeSnapshot( - *Utils::OpenHandle(*title), internal_type, control, resolver)); + isolate->heap_profiler()->TakeSnapshot( + *Utils::OpenHandle(*title), control, resolver)); +} + + +const HeapSnapshot* HeapProfiler::TakeHeapSnapshot( + Handle<String> title, + ActivityControl* control, + ObjectNameResolver* resolver) { + return reinterpret_cast<const HeapSnapshot*>( + reinterpret_cast<i::HeapProfiler*>(this)->TakeSnapshot( + *Utils::OpenHandle(*title), control, resolver)); } void HeapProfiler::StartHeapObjectsTracking() { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapProfiler::StartHeapObjectsTracking"); - i::HeapProfiler::StartHeapObjectsTracking(); + isolate->heap_profiler()->StartHeapObjectsTracking(); +} + + +void HeapProfiler::StartTrackingHeapObjects() { + reinterpret_cast<i::HeapProfiler*>(this)->StartHeapObjectsTracking(); } void HeapProfiler::StopHeapObjectsTracking() { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapProfiler::StopHeapObjectsTracking"); - i::HeapProfiler::StopHeapObjectsTracking(); + isolate->heap_profiler()->StopHeapObjectsTracking(); +} + + +void HeapProfiler::StopTrackingHeapObjects() { + reinterpret_cast<i::HeapProfiler*>(this)->StopHeapObjectsTracking(); } SnapshotObjectId HeapProfiler::PushHeapObjectsStats(OutputStream* stream) { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapProfiler::PushHeapObjectsStats"); - return i::HeapProfiler::PushHeapObjectsStats(stream); + return isolate->heap_profiler()->PushHeapObjectsStats(stream); +} + + +SnapshotObjectId HeapProfiler::GetHeapStats(OutputStream* stream) { + return reinterpret_cast<i::HeapProfiler*>(this)->PushHeapObjectsStats(stream); } void HeapProfiler::DeleteAllSnapshots() { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapProfiler::DeleteAllSnapshots"); - i::HeapProfiler::DeleteAllSnapshots(); + isolate->heap_profiler()->DeleteAllSnapshots(); +} + + +void HeapProfiler::DeleteAllHeapSnapshots() { + reinterpret_cast<i::HeapProfiler*>(this)->DeleteAllSnapshots(); } @@ -6880,6 +6982,13 @@ void HeapProfiler::DefineWrapperClass(uint16_t class_id, } +void HeapProfiler::SetWrapperClassInfoProvider(uint16_t class_id, + WrapperInfoCallback callback) { + reinterpret_cast<i::HeapProfiler*>(this)->DefineWrapperClass(class_id, + callback); +} + + int HeapProfiler::GetPersistentHandleCount() { i::Isolate* isolate = i::Isolate::Current(); return isolate->global_handles()->NumberOfGlobalHandles(); @@ -6887,7 +6996,13 @@ int HeapProfiler::GetPersistentHandleCount() { size_t HeapProfiler::GetMemorySizeUsedByProfiler() { - return i::HeapProfiler::GetMemorySizeUsedByProfiler(); + return i::Isolate::Current()->heap_profiler()->GetMemorySizeUsedByProfiler(); +} + + +size_t HeapProfiler::GetProfilerMemorySize() { + return reinterpret_cast<i::HeapProfiler*>(this)-> + GetMemorySizeUsedByProfiler(); } @@ -7082,7 +7197,7 @@ DeferredHandles::~DeferredHandles() { isolate_->UnlinkDeferredHandles(this); for (int i = 0; i < blocks_.length(); i++) { -#ifdef DEBUG +#ifdef ENABLE_EXTRA_CHECKS HandleScope::ZapRange(blocks_[i], &blocks_[i][kHandleBlockSize]); #endif isolate_->handle_scope_implementer()->ReturnBlock(blocks_[i]); diff --git a/deps/v8/src/api.h b/deps/v8/src/api.h index ac6b8342c..d73646d99 100644 --- a/deps/v8/src/api.h +++ b/deps/v8/src/api.h @@ -294,6 +294,9 @@ MAKE_TO_LOCAL(ToLocal, DeclaredAccessorDescriptor, DeclaredAccessorDescriptor) v8::internal::Handle<v8::internal::To> Utils::OpenHandle( \ const v8::From* that, bool allow_empty_handle) { \ EXTRA_CHECK(allow_empty_handle || that != NULL); \ + EXTRA_CHECK(that == NULL || \ + !(*reinterpret_cast<v8::internal::To**>( \ + const_cast<v8::From*>(that)))->IsFailure()); \ return v8::internal::Handle<v8::internal::To>( \ reinterpret_cast<v8::internal::To**>(const_cast<v8::From*>(that))); \ } @@ -569,8 +572,8 @@ void HandleScopeImplementer::DeleteExtensions(internal::Object** prev_limit) { #endif blocks_.RemoveLast(); -#ifdef DEBUG - v8::ImplementationUtilities::ZapHandleRange(block_start, block_limit); +#ifdef ENABLE_EXTRA_CHECKS + internal::HandleScope::ZapRange(block_start, block_limit); #endif if (spare_ != NULL) { DeleteArray(spare_); diff --git a/deps/v8/src/apiutils.h b/deps/v8/src/apiutils.h index 71c0e1c2c..9831f0866 100644 --- a/deps/v8/src/apiutils.h +++ b/deps/v8/src/apiutils.h @@ -67,10 +67,6 @@ class ImplementationUtilities { // Introduce an alias for the handle scope data to allow non-friends // to access the HandleScope data. typedef v8::HandleScope::Data HandleScopeData; - -#ifdef DEBUG - static void ZapHandleRange(internal::Object** begin, internal::Object** end); -#endif }; } // namespace v8 diff --git a/deps/v8/src/arm/builtins-arm.cc b/deps/v8/src/arm/builtins-arm.cc index 2946b355a..ebb9e1235 100644 --- a/deps/v8/src/arm/builtins-arm.cc +++ b/deps/v8/src/arm/builtins-arm.cc @@ -221,13 +221,12 @@ static void AllocateJSArray(MacroAssembler* masm, __ add(elements_array_end, elements_array_end, Operand(array_size, ASR, kSmiTagSize)); - __ AllocateInNewSpace( - elements_array_end, - result, - scratch1, - scratch2, - gc_required, - static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS)); + __ Allocate(elements_array_end, + result, + scratch1, + scratch2, + gc_required, + static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS)); // Allocated the JSArray. Now initialize the fields except for the elements // array. @@ -874,7 +873,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // r1: constructor function // r2: initial map __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset)); - __ AllocateInNewSpace(r3, r4, r5, r6, &rt_call, SIZE_IN_WORDS); + __ Allocate(r3, r4, r5, r6, &rt_call, SIZE_IN_WORDS); // Allocated the JSObject, now initialize the fields. Map is set to // initial map and properties and elements are set to empty fixed array. @@ -949,7 +948,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // r4: JSObject // r5: start of next object __ add(r0, r3, Operand(FixedArray::kHeaderSize / kPointerSize)); - __ AllocateInNewSpace( + __ Allocate( r0, r5, r6, @@ -1105,10 +1104,6 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, __ CompareObjectType(r0, r1, r3, FIRST_SPEC_OBJECT_TYPE); __ b(ge, &exit); - // Symbols are "objects". - __ CompareInstanceType(r1, r3, SYMBOL_TYPE); - __ b(eq, &exit); - // Throw away the result of the constructor invocation and use the // on-stack receiver as the result. __ bind(&use_receiver); diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index b1ffaea14..d982f2706 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -61,6 +61,17 @@ void KeyedLoadFastElementStub::InitializeInterfaceDescriptor( } +void KeyedStoreFastElementStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + static Register registers[] = { r2, r1, r0 }; + descriptor->register_param_count_ = 3; + descriptor->register_params_ = registers; + descriptor->deoptimization_handler_ = + FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure); +} + + void TransitionElementsKindStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { @@ -84,7 +95,7 @@ static void InitializeArrayConstructorDescriptor(Isolate* isolate, // stack param count needs (constructor pointer, and single argument) descriptor->stack_parameter_count_ = &r0; descriptor->register_params_ = registers; - descriptor->extra_expression_stack_count_ = 1; + descriptor->function_mode_ = JS_FUNCTION_STUB_MODE; descriptor->deoptimization_handler_ = FUNCTION_ADDR(ArrayConstructor_StubFailure); } @@ -2623,8 +2634,8 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm, OverwriteMode mode) { Register left = r1; Register right = r0; - Register scratch1 = r7; - Register scratch2 = r9; + Register scratch1 = r6; + Register scratch2 = r7; Register scratch3 = r4; ASSERT(smi_operands || (not_numbers != NULL)); @@ -2639,7 +2650,7 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm, __ JumpIfNotSmi(right, miss); } - Register heap_number_map = r6; + Register heap_number_map = r9; __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); switch (op) { @@ -4477,35 +4488,6 @@ void InstanceofStub::Generate(MacroAssembler* masm) { } -void ArrayLengthStub::Generate(MacroAssembler* masm) { - Label miss; - Register receiver; - if (kind() == Code::KEYED_LOAD_IC) { - // ----------- S t a t e ------------- - // -- lr : return address - // -- r0 : key - // -- r1 : receiver - // ----------------------------------- - __ cmp(r0, Operand(masm->isolate()->factory()->length_string())); - __ b(ne, &miss); - receiver = r1; - } else { - ASSERT(kind() == Code::LOAD_IC); - // ----------- S t a t e ------------- - // -- r2 : name - // -- lr : return address - // -- r0 : receiver - // -- sp[0] : receiver - // ----------------------------------- - receiver = r0; - } - - StubCompiler::GenerateLoadArrayLength(masm, receiver, r3, &miss); - __ bind(&miss); - StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind())); -} - - void FunctionPrototypeStub::Generate(MacroAssembler* masm) { Label miss; Register receiver; @@ -4780,7 +4762,7 @@ void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { __ add(r9, r9, Operand(Heap::kArgumentsObjectSize)); // Do the allocation of all three objects in one go. - __ AllocateInNewSpace(r9, r0, r3, r4, &runtime, TAG_OBJECT); + __ Allocate(r9, r0, r3, r4, &runtime, TAG_OBJECT); // r0 = address of new object(s) (tagged) // r2 = argument count (tagged) @@ -4956,13 +4938,8 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { __ add(r1, r1, Operand(Heap::kArgumentsObjectSizeStrict / kPointerSize)); // Do the allocation of both objects in one go. - __ AllocateInNewSpace(r1, - r0, - r2, - r3, - &runtime, - static_cast<AllocationFlags>(TAG_OBJECT | - SIZE_IN_WORDS)); + __ Allocate(r1, r0, r2, r3, &runtime, + static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS)); // Get the arguments boilerplate from the current native context. __ ldr(r4, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); @@ -5466,7 +5443,7 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) { (JSRegExpResult::kSize + FixedArray::kHeaderSize) / kPointerSize; __ mov(r5, Operand(r1, LSR, kSmiTagSize + kSmiShiftSize)); __ add(r2, r5, Operand(objects_size)); - __ AllocateInNewSpace( + __ Allocate( r2, // In: Size, in words. r0, // Out: Start of allocation (tagged). r3, // Scratch register. @@ -7408,33 +7385,31 @@ void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm, __ cmp(entity_name, tmp); __ b(eq, done); - if (i != kInlinedProbes - 1) { - // Load the hole ready for use below: - __ LoadRoot(tmp, Heap::kTheHoleValueRootIndex); + // Load the hole ready for use below: + __ LoadRoot(tmp, Heap::kTheHoleValueRootIndex); - // Stop if found the property. - __ cmp(entity_name, Operand(Handle<Name>(name))); - __ b(eq, miss); + // Stop if found the property. + __ cmp(entity_name, Operand(Handle<Name>(name))); + __ b(eq, miss); - Label good; - __ cmp(entity_name, tmp); - __ b(eq, &good); + Label good; + __ cmp(entity_name, tmp); + __ b(eq, &good); - // Check if the entry name is not a unique name. - __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); - __ ldrb(entity_name, - FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); - __ tst(entity_name, Operand(kIsInternalizedMask)); - __ b(ne, &good); - __ cmp(entity_name, Operand(SYMBOL_TYPE)); - __ b(ne, miss); - - __ bind(&good); - - // Restore the properties. - __ ldr(properties, - FieldMemOperand(receiver, JSObject::kPropertiesOffset)); - } + // Check if the entry name is not a unique name. + __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); + __ ldrb(entity_name, + FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); + __ tst(entity_name, Operand(kIsInternalizedMask)); + __ b(ne, &good); + __ cmp(entity_name, Operand(SYMBOL_TYPE)); + __ b(ne, miss); + + __ bind(&good); + + // Restore the properties. + __ ldr(properties, + FieldMemOperand(receiver, JSObject::kPropertiesOffset)); } const int spill_mask = @@ -7987,6 +7962,9 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) { int parameter_count_offset = StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset; __ ldr(r1, MemOperand(fp, parameter_count_offset)); + if (function_mode_ == JS_FUNCTION_STUB_MODE) { + __ add(r1, r1, Operand(1)); + } masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE); __ mov(r1, Operand(r1, LSL, kPointerSizeLog2)); __ add(sp, sp, r1); diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index ff97ab509..1c829469c 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -207,7 +207,7 @@ void ElementsTransitionGenerator::GenerateSmiToDouble( // Use lr as a temporary register. __ mov(lr, Operand(r5, LSL, 2)); __ add(lr, lr, Operand(FixedDoubleArray::kHeaderSize)); - __ AllocateInNewSpace(lr, r6, r7, r9, &gc_required, DOUBLE_ALIGNMENT); + __ Allocate(lr, r6, r7, r9, &gc_required, DOUBLE_ALIGNMENT); // r6: destination FixedDoubleArray, not tagged as heap object. // Set destination FixedDoubleArray's length and map. @@ -348,7 +348,7 @@ void ElementsTransitionGenerator::GenerateDoubleToObject( // Allocate new FixedArray. __ mov(r0, Operand(FixedDoubleArray::kHeaderSize)); __ add(r0, r0, Operand(r5, LSL, 1)); - __ AllocateInNewSpace(r0, r6, r7, r9, &gc_required, NO_ALLOCATION_FLAGS); + __ Allocate(r0, r6, r7, r9, &gc_required, NO_ALLOCATION_FLAGS); // r6: destination FixedArray, not tagged as heap object // Set destination FixedDoubleArray's length and map. __ LoadRoot(r9, Heap::kFixedArrayMapRootIndex); @@ -691,7 +691,7 @@ void Code::PatchPlatformCodeAge(byte* sequence, uint32_t young_length; byte* young_sequence = GetNoCodeAgeSequence(&young_length); if (age == kNoAge) { - memcpy(sequence, young_sequence, young_length); + CopyBytes(sequence, young_sequence, young_length); CPU::FlushICache(sequence, young_length); } else { Code* stub = GetCodeAgeStub(age, parity); diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index 1df1649d3..6086645db 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -2764,28 +2764,6 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( } -void FullCodeGenerator::EmitIsSymbol(CallRuntime* expr) { - ZoneList<Expression*>* args = expr->arguments(); - ASSERT(args->length() == 1); - - VisitForAccumulatorValue(args->at(0)); - - Label materialize_true, materialize_false; - Label* if_true = NULL; - Label* if_false = NULL; - Label* fall_through = NULL; - context()->PrepareTest(&materialize_true, &materialize_false, - &if_true, &if_false, &fall_through); - - __ JumpIfSmi(r0, if_false); - __ CompareObjectType(r0, r1, r2, SYMBOL_TYPE); - PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - Split(eq, if_true, if_false, fall_through); - - context()->Plug(if_true, if_false); -} - - void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) { ZoneList<Expression*>* args = expr->arguments(); ASSERT(args->length() == 1); @@ -4292,6 +4270,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset)); __ tst(r1, Operand(1 << Map::kIsUndetectable)); Split(eq, if_true, if_false, fall_through); + } else if (check->Equals(isolate()->heap()->symbol_string())) { + __ JumpIfSmi(r0, if_false); + __ CompareObjectType(r0, r0, r1, SYMBOL_TYPE); + Split(eq, if_true, if_false, fall_through); } else if (check->Equals(isolate()->heap()->boolean_string())) { __ CompareRoot(r0, Heap::kTrueValueRootIndex); __ b(eq, if_true); @@ -4324,10 +4306,6 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ CompareRoot(r0, Heap::kNullValueRootIndex); __ b(eq, if_true); } - if (FLAG_harmony_symbols) { - __ CompareObjectType(r0, r0, r1, SYMBOL_TYPE); - __ b(eq, if_true); - } // Check for JS objects => true. __ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); __ b(lt, if_false); diff --git a/deps/v8/src/arm/lithium-arm.cc b/deps/v8/src/arm/lithium-arm.cc index 38884ce0a..f2b65efe8 100644 --- a/deps/v8/src/arm/lithium-arm.cc +++ b/deps/v8/src/arm/lithium-arm.cc @@ -871,6 +871,35 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { LInstruction* instr = current->CompileToLithium(this); if (instr != NULL) { +#if DEBUG + // Make sure that the lithium instruction has either no fixed register + // constraints in temps or the result OR no uses that are only used at + // start. If this invariant doesn't hold, the register allocator can decide + // to insert a split of a range immediately before the instruction due to an + // already allocated register needing to be used for the instruction's fixed + // register constraint. In this case, The register allocator won't see an + // interference between the split child and the use-at-start (it would if + // the it was just a plain use), so it is free to move the split child into + // the same register that is used for the use-at-start. + // See https://code.google.com/p/chromium/issues/detail?id=201590 + if (!(instr->ClobbersRegisters() && instr->ClobbersDoubleRegisters())) { + int fixed = 0; + int used_at_start = 0; + for (UseIterator it(instr); !it.Done(); it.Advance()) { + LUnallocated* operand = LUnallocated::cast(it.Current()); + if (operand->IsUsedAtStart()) ++used_at_start; + } + if (instr->Output() != NULL) { + if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed; + } + for (TempIterator it(instr); !it.Done(); it.Advance()) { + LUnallocated* operand = LUnallocated::cast(it.Current()); + if (operand->HasFixedPolicy()) ++fixed; + } + ASSERT(fixed == 0 || used_at_start == 0); + } +#endif + if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) { instr = AssignPointerMap(instr); } @@ -1115,7 +1144,7 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp); return DefineFixedDouble(result, d2); } else { - LOperand* input = UseRegisterAtStart(instr->value()); + LOperand* input = UseRegister(instr->value()); LOperand* temp = (op == kMathRound) ? FixedTemp(d3) : NULL; LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp); @@ -1711,12 +1740,6 @@ LInstruction* LChunkBuilder::DoClassOfTestAndBranch( } -LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) { - LOperand* array = UseRegisterAtStart(instr->value()); - return DefineAsRegister(new(zone()) LJSArrayLength(array)); -} - - LInstruction* LChunkBuilder::DoFixedArrayBaseLength( HFixedArrayBaseLength* instr) { LOperand* array = UseRegisterAtStart(instr->value()); @@ -1823,11 +1846,13 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { return AssignEnvironment(DefineAsRegister(res)); } else { ASSERT(to.IsInteger32()); - LOperand* value = UseRegisterAtStart(instr->value()); + LOperand* value = NULL; LInstruction* res = NULL; if (instr->value()->type().IsSmi()) { + value = UseRegisterAtStart(instr->value()); res = DefineAsRegister(new(zone()) LSmiUntag(value, false)); } else { + value = UseRegister(instr->value()); LOperand* temp1 = TempRegister(); LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister() : NULL; @@ -2205,7 +2230,7 @@ LInstruction* LChunkBuilder::DoTransitionElementsKind( LOperand* new_map_reg = TempRegister(); LTransitionElementsKind* result = new(zone()) LTransitionElementsKind(object, new_map_reg, NULL); - return DefineSameAsFirst(result); + return result; } else if (FLAG_compiled_transitions) { LTransitionElementsKind* result = new(zone()) LTransitionElementsKind(object, NULL, NULL); diff --git a/deps/v8/src/arm/lithium-arm.h b/deps/v8/src/arm/lithium-arm.h index f49e8ce4f..207faf46e 100644 --- a/deps/v8/src/arm/lithium-arm.h +++ b/deps/v8/src/arm/lithium-arm.h @@ -120,7 +120,6 @@ class LCodeGen; V(IsStringAndBranch) \ V(IsSmiAndBranch) \ V(IsUndetectableAndBranch) \ - V(JSArrayLength) \ V(Label) \ V(LazyBailout) \ V(LoadContextSlot) \ @@ -1165,19 +1164,6 @@ class LCmpMapAndBranch: public LTemplateInstruction<0, 1, 1> { }; -class LJSArrayLength: public LTemplateInstruction<1, 1, 0> { - public: - explicit LJSArrayLength(LOperand* value) { - inputs_[0] = value; - } - - LOperand* value() { return inputs_[0]; } - - DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length") - DECLARE_HYDROGEN_ACCESSOR(JSArrayLength) -}; - - class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> { public: explicit LFixedArrayBaseLength(LOperand* value) { @@ -2114,7 +2100,7 @@ class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> { }; -class LTransitionElementsKind: public LTemplateInstruction<1, 1, 2> { +class LTransitionElementsKind: public LTemplateInstruction<0, 1, 2> { public: LTransitionElementsKind(LOperand* object, LOperand* new_map_temp, diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index 3ad86cfed..7bb3535ff 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -239,7 +239,7 @@ bool LCodeGen::GeneratePrologue() { __ str(r0, target); // Update the write barrier. This clobbers r3 and r0. __ RecordWriteContextSlot( - cp, target.offset(), r0, r3, kLRHasBeenSaved, kSaveFPRegs); + cp, target.offset(), r0, r3, GetLinkRegisterState(), kSaveFPRegs); } } Comment(";;; End allocate local context"); @@ -1918,13 +1918,6 @@ void LCodeGen::DoConstantT(LConstantT* instr) { } -void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { - Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->value()); - __ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset)); -} - - void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) { Register result = ToRegister(instr->result()); Register array = ToRegister(instr->value()); @@ -2301,6 +2294,12 @@ void LCodeGen::DoBranch(LBranch* instr) { __ bind(¬_string); } + if (expected.Contains(ToBooleanStub::SYMBOL)) { + // Symbol value -> true. + __ CompareInstanceType(map, ip, SYMBOL_TYPE); + __ b(eq, true_label); + } + if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { CpuFeatureScope scope(masm(), VFP2); // heap number -> false iff +0, -0, or NaN. @@ -3075,7 +3074,7 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { target.offset(), value, scratch, - kLRHasBeenSaved, + GetLinkRegisterState(), kSaveFPRegs, EMIT_REMEMBERED_SET, check_needed); @@ -4367,7 +4366,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { HeapObject::kMapOffset, scratch, temp, - kLRHasBeenSaved, + GetLinkRegisterState(), kSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); @@ -4386,7 +4385,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { offset, value, scratch, - kLRHasBeenSaved, + GetLinkRegisterState(), kSaveFPRegs, EMIT_REMEMBERED_SET, check_needed); @@ -4401,7 +4400,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { offset, value, object, - kLRHasBeenSaved, + GetLinkRegisterState(), kSaveFPRegs, EMIT_REMEMBERED_SET, check_needed); @@ -4602,7 +4601,7 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { __ RecordWrite(elements, key, value, - kLRHasBeenSaved, + GetLinkRegisterState(), kSaveFPRegs, EMIT_REMEMBERED_SET, check_needed); @@ -4654,7 +4653,7 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { __ str(new_map_reg, FieldMemOperand(object_reg, HeapObject::kMapOffset)); // Write barrier. __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, - scratch, kLRHasBeenSaved, kDontSaveFPRegs); + scratch, GetLinkRegisterState(), kDontSaveFPRegs); } else if (FLAG_compiled_transitions) { PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); __ Move(r0, object_reg); @@ -4897,10 +4896,11 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) { // Convert unsigned integer with specified number of leading zeroes in binary // representation to IEEE 754 double. -// Integer to convert is passed in register hiword. +// Integer to convert is passed in register src. // Resulting double is returned in registers hiword:loword. // This functions does not work correctly for 0. static void GenerateUInt2Double(MacroAssembler* masm, + Register src, Register hiword, Register loword, Register scratch, @@ -4914,13 +4914,13 @@ static void GenerateUInt2Double(MacroAssembler* masm, kBitsPerInt - mantissa_shift_for_hi_word; masm->mov(scratch, Operand(biased_exponent << HeapNumber::kExponentShift)); if (mantissa_shift_for_hi_word > 0) { - masm->mov(loword, Operand(hiword, LSL, mantissa_shift_for_lo_word)); + masm->mov(loword, Operand(src, LSL, mantissa_shift_for_lo_word)); masm->orr(hiword, scratch, - Operand(hiword, LSR, mantissa_shift_for_hi_word)); + Operand(src, LSR, mantissa_shift_for_hi_word)); } else { masm->mov(loword, Operand::Zero()); masm->orr(hiword, scratch, - Operand(hiword, LSL, -mantissa_shift_for_hi_word)); + Operand(src, LSL, -mantissa_shift_for_hi_word)); } // If least significant bit of biased exponent was not 1 it was corrupted @@ -4969,17 +4969,17 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, __ vmov(flt_scratch, src); __ vcvt_f64_u32(dbl_scratch, flt_scratch); } else { - Label no_leading_zero, done; + Label no_leading_zero, convert_done; __ tst(src, Operand(0x80000000)); __ b(ne, &no_leading_zero); // Integer has one leading zeros. - GenerateUInt2Double(masm(), sfpd_hi, sfpd_lo, r9, 1); - __ b(&done); + GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, r9, 1); + __ b(&convert_done); __ bind(&no_leading_zero); - GenerateUInt2Double(masm(), sfpd_hi, sfpd_lo, r9, 0); - __ b(&done); + GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, r9, 0); + __ bind(&convert_done); } } @@ -4996,10 +4996,18 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, // TODO(3095996): Put a valid pointer value in the stack slot where the result // register is stored, as this register is in the pointer map, but contains an // integer value. + if (!CpuFeatures::IsSupported(VFP2)) { + // Preserve sfpd_lo. + __ mov(r9, sfpd_lo); + } __ mov(ip, Operand::Zero()); __ StoreToSafepointRegisterSlot(ip, dst); CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); __ Move(dst, r0); + if (!CpuFeatures::IsSupported(VFP2)) { + // Restore sfpd_lo. + __ mov(sfpd_lo, r9); + } __ sub(dst, dst, Operand(kHeapObjectTag)); // Done. Put the value in dbl_scratch into the value of the allocated heap @@ -5671,12 +5679,12 @@ void LCodeGen::DoAllocate(LAllocate* instr) { __ Allocate(size, result, scratch, scratch2, deferred->entry(), flags); } else { Register size = ToRegister(instr->size()); - __ AllocateInNewSpace(size, - result, - scratch, - scratch2, - deferred->entry(), - flags); + __ Allocate(size, + result, + scratch, + scratch2, + deferred->entry(), + flags); } __ bind(deferred->exit()); @@ -6074,6 +6082,11 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, __ tst(ip, Operand(1 << Map::kIsUndetectable)); final_branch_condition = eq; + } else if (type_name->Equals(heap()->symbol_string())) { + __ JumpIfSmi(input, false_label); + __ CompareObjectType(input, input, scratch, SYMBOL_TYPE); + final_branch_condition = eq; + } else if (type_name->Equals(heap()->boolean_string())) { __ CompareRoot(input, Heap::kTrueValueRootIndex); __ b(eq, true_label); @@ -6108,15 +6121,8 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, __ CompareRoot(input, Heap::kNullValueRootIndex); __ b(eq, true_label); } - if (FLAG_harmony_symbols) { - __ CompareObjectType(input, input, scratch, SYMBOL_TYPE); - __ b(eq, true_label); - __ CompareInstanceType(input, scratch, - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); - } else { - __ CompareObjectType(input, input, scratch, - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); - } + __ CompareObjectType(input, input, scratch, + FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); __ b(lt, false_label); __ CompareInstanceType(input, scratch, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); __ b(gt, false_label); diff --git a/deps/v8/src/arm/lithium-codegen-arm.h b/deps/v8/src/arm/lithium-codegen-arm.h index d1f712ab8..686241db7 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.h +++ b/deps/v8/src/arm/lithium-codegen-arm.h @@ -87,6 +87,10 @@ class LCodeGen BASE_EMBEDDED { return !NeedsEagerFrame() && info()->is_deferred_calling(); } + LinkRegisterStatus GetLinkRegisterState() const { + return frame_is_built_ ? kLRHasBeenSaved : kLRHasNotBeenSaved; + } + // Support for converting LOperands to assembler types. // LOperand must be a register. Register ToRegister(LOperand* op) const; diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index e0e77cfd3..bacf570c3 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -708,15 +708,14 @@ void MacroAssembler::Ldrd(Register dst1, Register dst2, const MemOperand& src, Condition cond) { ASSERT(src.rm().is(no_reg)); ASSERT(!dst1.is(lr)); // r14. - ASSERT_EQ(0, dst1.code() % 2); - ASSERT_EQ(dst1.code() + 1, dst2.code()); // V8 does not use this addressing mode, so the fallback code // below doesn't support it yet. ASSERT((src.am() != PreIndex) && (src.am() != NegPreIndex)); // Generate two ldr instructions if ldrd is not available. - if (CpuFeatures::IsSupported(ARMv7) && !predictable_code_size()) { + if (CpuFeatures::IsSupported(ARMv7) && !predictable_code_size() && + (dst1.code() % 2 == 0) && (dst1.code() + 1 == dst2.code())) { CpuFeatureScope scope(this, ARMv7); ldrd(dst1, dst2, src, cond); } else { @@ -750,15 +749,14 @@ void MacroAssembler::Strd(Register src1, Register src2, const MemOperand& dst, Condition cond) { ASSERT(dst.rm().is(no_reg)); ASSERT(!src1.is(lr)); // r14. - ASSERT_EQ(0, src1.code() % 2); - ASSERT_EQ(src1.code() + 1, src2.code()); // V8 does not use this addressing mode, so the fallback code // below doesn't support it yet. ASSERT((dst.am() != PreIndex) && (dst.am() != NegPreIndex)); // Generate two str instructions if strd is not available. - if (CpuFeatures::IsSupported(ARMv7) && !predictable_code_size()) { + if (CpuFeatures::IsSupported(ARMv7) && !predictable_code_size() && + (src1.code() % 2 == 0) && (src1.code() + 1 == src2.code())) { CpuFeatureScope scope(this, ARMv7); strd(src1, src2, dst, cond); } else { @@ -1671,13 +1669,12 @@ void MacroAssembler::Allocate(int object_size, } -void MacroAssembler::AllocateInNewSpace(Register object_size, - Register result, - Register scratch1, - Register scratch2, - Label* gc_required, - AllocationFlags flags) { - ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0); +void MacroAssembler::Allocate(Register object_size, + Register result, + Register scratch1, + Register scratch2, + Label* gc_required, + AllocationFlags flags) { if (!FLAG_inline_new) { if (emit_debug_code()) { // Trash the registers to simulate an allocation failure. @@ -1703,20 +1700,20 @@ void MacroAssembler::AllocateInNewSpace(Register object_size, // The values must be adjacent in memory to allow the use of LDM. // Also, assert that the registers are numbered such that the values // are loaded in the correct order. - ExternalReference new_space_allocation_top = - ExternalReference::new_space_allocation_top_address(isolate()); - ExternalReference new_space_allocation_limit = - ExternalReference::new_space_allocation_limit_address(isolate()); + ExternalReference allocation_top = + AllocationUtils::GetAllocationTopReference(isolate(), flags); + ExternalReference allocation_limit = + AllocationUtils::GetAllocationLimitReference(isolate(), flags); intptr_t top = - reinterpret_cast<intptr_t>(new_space_allocation_top.address()); + reinterpret_cast<intptr_t>(allocation_top.address()); intptr_t limit = - reinterpret_cast<intptr_t>(new_space_allocation_limit.address()); + reinterpret_cast<intptr_t>(allocation_limit.address()); ASSERT((limit - top) == kPointerSize); ASSERT(result.code() < ip.code()); // Set up allocation top address. Register topaddr = scratch1; - mov(topaddr, Operand(new_space_allocation_top)); + mov(topaddr, Operand(allocation_top)); // This code stores a temporary value in ip. This is OK, as the code below // does not need ip for implicit literal generation. @@ -1739,6 +1736,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size, 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), SetCC); Label aligned; @@ -1809,12 +1807,12 @@ void MacroAssembler::AllocateTwoByteString(Register result, and_(scratch1, scratch1, Operand(~kObjectAlignmentMask)); // Allocate two-byte string in new space. - AllocateInNewSpace(scratch1, - result, - scratch2, - scratch3, - gc_required, - TAG_OBJECT); + Allocate(scratch1, + result, + scratch2, + scratch3, + gc_required, + TAG_OBJECT); // Set the map, length and hash field. InitializeNewString(result, @@ -1840,12 +1838,12 @@ void MacroAssembler::AllocateAsciiString(Register result, and_(scratch1, scratch1, Operand(~kObjectAlignmentMask)); // Allocate ASCII string in new space. - AllocateInNewSpace(scratch1, - result, - scratch2, - scratch3, - gc_required, - TAG_OBJECT); + Allocate(scratch1, + result, + scratch2, + scratch3, + gc_required, + TAG_OBJECT); // Set the map, length and hash field. InitializeNewString(result, @@ -2499,9 +2497,9 @@ void MacroAssembler::TryInt32Floor(Register result, void MacroAssembler::ECMAConvertNumberToInt32(Register source, Register result, - Register scratch, - Register input_high, Register input_low, + Register input_high, + Register scratch, DwVfpRegister double_scratch1, DwVfpRegister double_scratch2) { if (CpuFeatures::IsSupported(VFP2)) { @@ -2578,24 +2576,26 @@ void MacroAssembler::ECMAToInt32NoVFP(Register result, Ubfx(scratch, input_high, HeapNumber::kExponentShift, HeapNumber::kExponentBits); - // Load scratch with exponent - 1. This is faster than loading - // with exponent because Bias + 1 = 1024 which is an *ARM* immediate value. - sub(scratch, scratch, Operand(HeapNumber::kExponentBias + 1)); + // Load scratch with exponent. + sub(scratch, scratch, Operand(HeapNumber::kExponentBias)); // If exponent is negative, 0 < input < 1, the result is 0. // If exponent is greater than or equal to 84, the 32 less significant // bits are 0s (2^84 = 1, 52 significant bits, 32 uncoded bits), // the result is 0. // This test also catch Nan and infinities which also return 0. - // Compare exponent with 84 (compare exponent - 1 with 83). - cmp(scratch, Operand(83)); + cmp(scratch, Operand(84)); // We do an unsigned comparison so negative numbers are treated as big // positive number and the two tests above are done in one test. b(hs, &out_of_range); - // Load scratch with 20 - exponent (load with 19 - (exponent - 1)). - rsb(scratch, scratch, Operand(19), SetCC); + // Load scratch with 20 - exponent. + rsb(scratch, scratch, Operand(20), SetCC); b(mi, &both); + // Test 0 and -0. + bic(result, input_high, Operand(HeapNumber::kSignMask)); + orr(result, result, Operand(input_low), SetCC); + b(eq, &done); // 0 <= exponent <= 20, shift only input_high. // Scratch contains: 20 - exponent. Ubfx(result, input_high, diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index 5cbe995d7..958fcacb3 100644 --- a/deps/v8/src/arm/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -679,12 +679,12 @@ class MacroAssembler: public Assembler { Label* gc_required, AllocationFlags flags); - void AllocateInNewSpace(Register object_size, - Register result, - Register scratch1, - Register scratch2, - Label* gc_required, - AllocationFlags flags); + void Allocate(Register object_size, + Register result, + Register scratch1, + Register scratch2, + Label* gc_required, + AllocationFlags flags); // Undo allocation in new space. The object passed and objects allocated after // it will no longer be allocated. The caller must make sure that no pointers @@ -960,9 +960,9 @@ class MacroAssembler: public Assembler { // Exits with 'result' holding the answer. void ECMAConvertNumberToInt32(Register source, Register result, - Register scratch, - Register input_high, Register input_low, + Register input_high, + Register scratch, DwVfpRegister double_scratch1, DwVfpRegister double_scratch2); diff --git a/deps/v8/src/arm/simulator-arm.cc b/deps/v8/src/arm/simulator-arm.cc index b7bc83905..2551e14e4 100644 --- a/deps/v8/src/arm/simulator-arm.cc +++ b/deps/v8/src/arm/simulator-arm.cc @@ -112,8 +112,8 @@ void ArmDebugger::Stop(Instruction* instr) { ASSERT(msg != NULL); // Update this stop description. - if (isWatchedStop(code) && !watched_stops[code].desc) { - watched_stops[code].desc = msg; + if (isWatchedStop(code) && !watched_stops_[code].desc) { + watched_stops_[code].desc = msg; } if (strlen(msg) > 0) { @@ -141,8 +141,8 @@ void ArmDebugger::Stop(Instruction* instr) { char* msg = *reinterpret_cast<char**>(sim_->get_pc() + Instruction::kInstrSize); // Update this stop description. - if (sim_->isWatchedStop(code) && !sim_->watched_stops[code].desc) { - sim_->watched_stops[code].desc = msg; + if (sim_->isWatchedStop(code) && !sim_->watched_stops_[code].desc) { + sim_->watched_stops_[code].desc = msg; } // Print the stop message and code if it is not the default code. if (code != kMaxStopCode) { @@ -1880,14 +1880,14 @@ bool Simulator::isEnabledStop(uint32_t code) { ASSERT(code <= kMaxStopCode); // Unwatched stops are always enabled. return !isWatchedStop(code) || - !(watched_stops[code].count & kStopDisabledBit); + !(watched_stops_[code].count & kStopDisabledBit); } void Simulator::EnableStop(uint32_t code) { ASSERT(isWatchedStop(code)); if (!isEnabledStop(code)) { - watched_stops[code].count &= ~kStopDisabledBit; + watched_stops_[code].count &= ~kStopDisabledBit; } } @@ -1895,7 +1895,7 @@ void Simulator::EnableStop(uint32_t code) { void Simulator::DisableStop(uint32_t code) { ASSERT(isWatchedStop(code)); if (isEnabledStop(code)) { - watched_stops[code].count |= kStopDisabledBit; + watched_stops_[code].count |= kStopDisabledBit; } } @@ -1903,13 +1903,13 @@ void Simulator::DisableStop(uint32_t code) { void Simulator::IncreaseStopCounter(uint32_t code) { ASSERT(code <= kMaxStopCode); ASSERT(isWatchedStop(code)); - if ((watched_stops[code].count & ~(1 << 31)) == 0x7fffffff) { + if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) { PrintF("Stop counter for code %i has overflowed.\n" "Enabling this code and reseting the counter to 0.\n", code); - watched_stops[code].count = 0; + watched_stops_[code].count = 0; EnableStop(code); } else { - watched_stops[code].count++; + watched_stops_[code].count++; } } @@ -1921,12 +1921,12 @@ void Simulator::PrintStopInfo(uint32_t code) { PrintF("Stop not watched."); } else { const char* state = isEnabledStop(code) ? "Enabled" : "Disabled"; - int32_t count = watched_stops[code].count & ~kStopDisabledBit; + int32_t count = watched_stops_[code].count & ~kStopDisabledBit; // Don't print the state of unused breakpoints. if (count != 0) { - if (watched_stops[code].desc) { + if (watched_stops_[code].desc) { PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", - code, code, state, count, watched_stops[code].desc); + code, code, state, count, watched_stops_[code].desc); } else { PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n", code, code, state, count); diff --git a/deps/v8/src/arm/simulator-arm.h b/deps/v8/src/arm/simulator-arm.h index 907a59066..b918ecf96 100644 --- a/deps/v8/src/arm/simulator-arm.h +++ b/deps/v8/src/arm/simulator-arm.h @@ -414,14 +414,14 @@ class Simulator { static const uint32_t kStopDisabledBit = 1 << 31; // A stop is enabled, meaning the simulator will stop when meeting the - // instruction, if bit 31 of watched_stops[code].count is unset. - // The value watched_stops[code].count & ~(1 << 31) indicates how many times + // instruction, if bit 31 of watched_stops_[code].count is unset. + // The value watched_stops_[code].count & ~(1 << 31) indicates how many times // the breakpoint was hit or gone through. struct StopCountAndDesc { uint32_t count; char* desc; }; - StopCountAndDesc watched_stops[kNumOfWatchedStops]; + StopCountAndDesc watched_stops_[kNumOfWatchedStops]; }; diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index 3350c56c1..f2d45e190 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -423,7 +423,7 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, // registers have their original values. void StubCompiler::GenerateStoreField(MacroAssembler* masm, Handle<JSObject> object, - int index, + LookupResult* lookup, Handle<Map> transition, Handle<Name> name, Register receiver_reg, @@ -436,16 +436,6 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, // r0 : value Label exit; - LookupResult lookup(masm->isolate()); - object->Lookup(*name, &lookup); - if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) { - // In sloppy mode, we could just return the value and be done. However, we - // might be in strict mode, where we have to throw. Since we cannot tell, - // go into slow case unconditionally. - __ jmp(miss_label); - return; - } - // Check that the map of the object hasn't changed. CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS : REQUIRE_EXACT_MAP; @@ -460,8 +450,9 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, // Check that we are allowed to write this. if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { JSObject* holder; - if (lookup.IsFound()) { - holder = lookup.holder(); + // holder == object indicates that no property was found. + if (lookup->holder() != *object) { + holder = lookup->holder(); } else { // Find the top object. holder = *object; @@ -469,8 +460,19 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, holder = JSObject::cast(holder->GetPrototype()); } while (holder->GetPrototype()->IsJSObject()); } - CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg, - scratch1, scratch2, name, miss_restore_name); + Register holder_reg = CheckPrototypes( + object, receiver_reg, Handle<JSObject>(holder), name_reg, + scratch1, scratch2, name, miss_restore_name); + // If no property was found, and the holder (the last object in the + // prototype chain) is in slow mode, we need to do a negative lookup on the + // holder. + if (lookup->holder() == *object && + !holder->HasFastProperties() && + !holder->IsJSGlobalProxy() && + !holder->IsJSGlobalObject()) { + GenerateDictionaryNegativeLookup( + masm, miss_restore_name, holder_reg, name, scratch1, scratch2); + } } // Stub never generated for non-global objects that require access @@ -492,6 +494,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, return; } + int index; if (!transition.is_null()) { // Update the map of the object. __ mov(scratch1, Operand(transition)); @@ -507,6 +510,10 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); + index = transition->instance_descriptors()->GetFieldIndex( + transition->LastAdded()); + } else { + index = lookup->GetFieldIndex().field_index(); } // Adjust for the number of properties stored in the object. Even in the @@ -2391,6 +2398,12 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object, // Check that the object is a symbol. __ CompareObjectType(r1, r1, r3, SYMBOL_TYPE); __ b(ne, &miss); + // Check that the maps starting from the prototype haven't changed. + GenerateDirectLoadGlobalFunctionPrototype( + masm(), Context::SYMBOL_FUNCTION_INDEX, r0, &miss); + CheckPrototypes( + Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))), + r0, holder, r3, r1, r4, name, &miss); break; case NUMBER_CHECK: { @@ -2982,7 +2995,7 @@ Handle<Code> ConstructStubCompiler::CompileConstructStub( __ cmp(r3, Operand(instance_size >> kPointerSizeLog2)); __ Check(eq, "Instance size of initial map changed."); #endif - __ AllocateInNewSpace(r3, r4, r5, r6, &generic_stub_call, SIZE_IN_WORDS); + __ Allocate(r3, r4, r5, r6, &generic_stub_call, SIZE_IN_WORDS); // Allocated the JSObject, now initialize the fields. Map is set to initial // map and properties and elements are set to empty fixed array. diff --git a/deps/v8/src/array.js b/deps/v8/src/array.js index 7cf744bed..936d00801 100644 --- a/deps/v8/src/array.js +++ b/deps/v8/src/array.js @@ -38,22 +38,21 @@ var visited_arrays = new InternalArray(); // Gets a sorted array of array keys. Useful for operations on sparse // arrays. Dupes have not been removed. -function GetSortedArrayKeys(array, intervals) { - var length = intervals.length; - var keys = []; - for (var k = 0; k < length; k++) { - var key = intervals[k]; - if (key < 0) { - var j = -1 - key; - var limit = j + intervals[++k]; - for (; j < limit; j++) { - var e = array[j]; - if (!IS_UNDEFINED(e) || j in array) { - keys.push(j); - } +function GetSortedArrayKeys(array, indices) { + var keys = new InternalArray(); + if (IS_NUMBER(indices)) { + // It's an interval + var limit = indices; + for (var i = 0; i < limit; ++i) { + var e = array[i]; + if (!IS_UNDEFINED(e) || i in array) { + keys.push(i); } - } else { - // The case where key is undefined also ends here. + } + } else { + var length = indices.length; + for (var k = 0; k < length; ++k) { + var key = indices[k]; if (!IS_UNDEFINED(key)) { var e = array[key]; if (!IS_UNDEFINED(e) || key in array) { @@ -61,8 +60,8 @@ function GetSortedArrayKeys(array, intervals) { } } } + %_CallFunction(keys, function(a, b) { return a - b; }, ArraySort); } - %_CallFunction(keys, function(a, b) { return a - b; }, ArraySort); return keys; } @@ -217,34 +216,21 @@ function ConvertToLocaleString(e) { // special array operations to handle sparse arrays in a sensible fashion. function SmartSlice(array, start_i, del_count, len, deleted_elements) { // Move deleted elements to a new array (the return value from splice). - // Intervals array can contain keys and intervals. See comment in Concat. - var intervals = %GetArrayKeys(array, start_i + del_count); - var length = intervals.length; - for (var k = 0; k < length; k++) { - var key = intervals[k]; - if (key < 0) { - var j = -1 - key; - var interval_limit = j + intervals[++k]; - if (j < start_i) { - j = start_i; - } - for (; j < interval_limit; j++) { - // ECMA-262 15.4.4.12 line 10. The spec could also be - // interpreted such that %HasLocalProperty would be the - // appropriate test. We follow KJS in consulting the - // prototype. - var current = array[j]; - if (!IS_UNDEFINED(current) || j in array) { - deleted_elements[j - start_i] = current; - } + var indices = %GetArrayKeys(array, start_i + del_count); + if (IS_NUMBER(indices)) { + var limit = indices; + for (var i = start_i; i < limit; ++i) { + var current = array[i]; + if (!IS_UNDEFINED(current) || i in array) { + deleted_elements[i - start_i] = current; } - } else { + } + } else { + var length = indices.length; + for (var k = 0; k < length; ++k) { + var key = indices[k]; if (!IS_UNDEFINED(key)) { if (key >= start_i) { - // ECMA-262 15.4.4.12 line 10. The spec could also be - // interpreted such that %HasLocalProperty would be the - // appropriate test. We follow KJS in consulting the - // prototype. var current = array[key]; if (!IS_UNDEFINED(current) || key in array) { deleted_elements[key - start_i] = current; @@ -261,50 +247,32 @@ function SmartSlice(array, start_i, del_count, len, deleted_elements) { function SmartMove(array, start_i, del_count, len, num_additional_args) { // Move data to new array. var new_array = new InternalArray(len - del_count + num_additional_args); - var intervals = %GetArrayKeys(array, len); - var length = intervals.length; - for (var k = 0; k < length; k++) { - var key = intervals[k]; - if (key < 0) { - var j = -1 - key; - var interval_limit = j + intervals[++k]; - while (j < start_i && j < interval_limit) { - // The spec could also be interpreted such that - // %HasLocalProperty would be the appropriate test. We follow - // KJS in consulting the prototype. - var current = array[j]; - if (!IS_UNDEFINED(current) || j in array) { - new_array[j] = current; - } - j++; + var indices = %GetArrayKeys(array, len); + if (IS_NUMBER(indices)) { + var limit = indices; + for (var i = 0; i < start_i && i < limit; ++i) { + var current = array[i]; + if (!IS_UNDEFINED(current) || i in array) { + new_array[i] = current; } - j = start_i + del_count; - while (j < interval_limit) { - // ECMA-262 15.4.4.12 lines 24 and 41. The spec could also be - // interpreted such that %HasLocalProperty would be the - // appropriate test. We follow KJS in consulting the - // prototype. - var current = array[j]; - if (!IS_UNDEFINED(current) || j in array) { - new_array[j - del_count + num_additional_args] = current; - } - j++; + } + for (var i = start_i + del_count; i < limit; ++i) { + var current = array[i]; + if (!IS_UNDEFINED(current) || i in array) { + new_array[i - del_count + num_additional_args] = current; } - } else { + } + } else { + var length = indices.length; + for (var k = 0; k < length; ++k) { + var key = indices[k]; if (!IS_UNDEFINED(key)) { if (key < start_i) { - // The spec could also be interpreted such that - // %HasLocalProperty would be the appropriate test. We follow - // KJS in consulting the prototype. var current = array[key]; if (!IS_UNDEFINED(current) || key in array) { new_array[key] = current; } } else if (key >= start_i + del_count) { - // ECMA-262 15.4.4.12 lines 24 and 41. The spec could also - // be interpreted such that %HasLocalProperty would be the - // appropriate test. We follow KJS in consulting the - // prototype. var current = array[key]; if (!IS_UNDEFINED(current) || key in array) { new_array[key - del_count + num_additional_args] = current; @@ -887,24 +855,22 @@ function ArraySort(comparefn) { var max = 0; for (var proto = %GetPrototype(obj); proto; proto = %GetPrototype(proto)) { var indices = %GetArrayKeys(proto, length); - if (indices.length > 0) { - if (indices[0] == -1) { - // It's an interval. - var proto_length = indices[1]; - for (var i = 0; i < proto_length; i++) { - if (!obj.hasOwnProperty(i) && proto.hasOwnProperty(i)) { - obj[i] = proto[i]; - if (i >= max) { max = i + 1; } - } + if (IS_NUMBER(indices)) { + // It's an interval. + var proto_length = indices; + for (var i = 0; i < proto_length; i++) { + if (!obj.hasOwnProperty(i) && proto.hasOwnProperty(i)) { + obj[i] = proto[i]; + if (i >= max) { max = i + 1; } } - } else { - for (var i = 0; i < indices.length; i++) { - var index = indices[i]; - if (!IS_UNDEFINED(index) && - !obj.hasOwnProperty(index) && proto.hasOwnProperty(index)) { - obj[index] = proto[index]; - if (index >= max) { max = index + 1; } - } + } + } else { + for (var i = 0; i < indices.length; i++) { + var index = indices[i]; + if (!IS_UNDEFINED(index) && + !obj.hasOwnProperty(index) && proto.hasOwnProperty(index)) { + obj[index] = proto[index]; + if (index >= max) { max = index + 1; } } } } @@ -918,22 +884,20 @@ function ArraySort(comparefn) { var ShadowPrototypeElements = function(obj, from, to) { for (var proto = %GetPrototype(obj); proto; proto = %GetPrototype(proto)) { var indices = %GetArrayKeys(proto, to); - if (indices.length > 0) { - if (indices[0] == -1) { - // It's an interval. - var proto_length = indices[1]; - for (var i = from; i < proto_length; i++) { - if (proto.hasOwnProperty(i)) { - obj[i] = void 0; - } + if (IS_NUMBER(indices)) { + // It's an interval. + var proto_length = indices; + for (var i = from; i < proto_length; i++) { + if (proto.hasOwnProperty(i)) { + obj[i] = void 0; } - } else { - for (var i = 0; i < indices.length; i++) { - var index = indices[i]; - if (!IS_UNDEFINED(index) && from <= index && - proto.hasOwnProperty(index)) { - obj[index] = void 0; - } + } + } else { + for (var i = 0; i < indices.length; i++) { + var index = indices[i]; + if (!IS_UNDEFINED(index) && from <= index && + proto.hasOwnProperty(index)) { + obj[index] = void 0; } } } @@ -1284,18 +1248,15 @@ function ArrayIndexOf(element, index) { var min = index; var max = length; if (UseSparseVariant(this, length, IS_ARRAY(this))) { - var intervals = %GetArrayKeys(this, length); - if (intervals.length == 2 && intervals[0] < 0) { - // A single interval. - var intervalMin = -(intervals[0] + 1); - var intervalMax = intervalMin + intervals[1]; - if (min < intervalMin) min = intervalMin; - max = intervalMax; // Capped by length already. + var indices = %GetArrayKeys(this, length); + if (IS_NUMBER(indices)) { + // It's an interval. + max = indices; // Capped by length already. // Fall through to loop below. } else { - if (intervals.length == 0) return -1; + if (indices.length == 0) return -1; // Get all the keys in sorted order. - var sortedKeys = GetSortedArrayKeys(this, intervals); + var sortedKeys = GetSortedArrayKeys(this, indices); var n = sortedKeys.length; var i = 0; while (i < n && sortedKeys[i] < index) i++; @@ -1345,18 +1306,15 @@ function ArrayLastIndexOf(element, index) { var min = 0; var max = index; if (UseSparseVariant(this, length, IS_ARRAY(this))) { - var intervals = %GetArrayKeys(this, index + 1); - if (intervals.length == 2 && intervals[0] < 0) { - // A single interval. - var intervalMin = -(intervals[0] + 1); - var intervalMax = intervalMin + intervals[1]; - if (min < intervalMin) min = intervalMin; - max = intervalMax; // Capped by index already. + var indices = %GetArrayKeys(this, index + 1); + if (IS_NUMBER(indices)) { + // It's an interval. + max = indices; // Capped by index already. // Fall through to loop below. } else { - if (intervals.length == 0) return -1; + if (indices.length == 0) return -1; // Get all the keys in sorted order. - var sortedKeys = GetSortedArrayKeys(this, intervals); + var sortedKeys = GetSortedArrayKeys(this, indices); var i = sortedKeys.length - 1; while (i >= 0) { var key = sortedKeys[i]; diff --git a/deps/v8/src/assembler.cc b/deps/v8/src/assembler.cc index 8536ca006..deef28b1f 100644 --- a/deps/v8/src/assembler.cc +++ b/deps/v8/src/assembler.cc @@ -927,20 +927,9 @@ void ExternalReference::InitializeMathExpData() { math_exp_log_table_array = new double[kTableSize]; for (int i = 0; i < kTableSize; i++) { double value = pow(2, i / kTableSizeDouble); - uint64_t bits = BitCast<uint64_t, double>(value); bits &= (static_cast<uint64_t>(1) << 52) - 1; double mantissa = BitCast<double, uint64_t>(bits); - - // <just testing> - uint64_t doublebits; - memcpy(&doublebits, &value, sizeof doublebits); - doublebits &= (static_cast<uint64_t>(1) << 52) - 1; - double mantissa2; - memcpy(&mantissa2, &doublebits, sizeof mantissa2); - CHECK_EQ(mantissa, mantissa2); - // </just testing> - math_exp_log_table_array[i] = mantissa; } diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc index 712bfd1b9..7d7a5b247 100644 --- a/deps/v8/src/ast.cc +++ b/deps/v8/src/ast.cc @@ -128,7 +128,8 @@ Assignment::Assignment(Isolate* isolate, pos_(pos), binary_operation_(NULL), assignment_id_(GetNextId(isolate)), - is_monomorphic_(false) { } + is_monomorphic_(false), + store_mode_(STANDARD_STORE) { } Token::Value Assignment::binary_op() const { @@ -413,12 +414,9 @@ void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle, is_monomorphic_ = oracle->LoadIsMonomorphicNormal(this); receiver_types_.Clear(); if (key()->IsPropertyName()) { - ArrayLengthStub array_stub(Code::LOAD_IC); FunctionPrototypeStub proto_stub(Code::LOAD_IC); StringLengthStub string_stub(Code::LOAD_IC, false); - if (oracle->LoadIsStub(this, &array_stub)) { - is_array_length_ = true; - } else if (oracle->LoadIsStub(this, &string_stub)) { + if (oracle->LoadIsStub(this, &string_stub)) { is_string_length_ = true; } else if (oracle->LoadIsStub(this, &proto_stub)) { is_function_prototype_ = true; @@ -455,9 +453,11 @@ void Assignment::RecordTypeFeedback(TypeFeedbackOracle* oracle, } else if (is_monomorphic_) { // Record receiver type for monomorphic keyed stores. receiver_types_.Add(oracle->StoreMonomorphicReceiverType(id), zone); + store_mode_ = oracle->GetStoreMode(id); } else if (oracle->StoreIsPolymorphic(id)) { receiver_types_.Reserve(kMaxKeyedPolymorphism, zone); oracle->CollectKeyedReceiverTypes(id, &receiver_types_); + store_mode_ = oracle->GetStoreMode(id); } } @@ -475,6 +475,7 @@ void CountOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle, receiver_types_.Reserve(kMaxKeyedPolymorphism, zone); oracle->CollectKeyedReceiverTypes(id, &receiver_types_); } + store_mode_ = oracle->GetStoreMode(id); } @@ -1061,6 +1062,7 @@ DONT_OPTIMIZE_NODE(ModuleVariable) DONT_OPTIMIZE_NODE(ModulePath) DONT_OPTIMIZE_NODE(ModuleUrl) DONT_OPTIMIZE_NODE(ModuleStatement) +DONT_OPTIMIZE_NODE(Yield) DONT_OPTIMIZE_NODE(WithStatement) DONT_OPTIMIZE_NODE(TryCatchStatement) DONT_OPTIMIZE_NODE(TryFinallyStatement) diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index 5debc74eb..dddfc835f 100644 --- a/deps/v8/src/ast.h +++ b/deps/v8/src/ast.h @@ -102,6 +102,7 @@ namespace internal { V(ObjectLiteral) \ V(ArrayLiteral) \ V(Assignment) \ + V(Yield) \ V(Throw) \ V(Property) \ V(Call) \ @@ -119,6 +120,10 @@ namespace internal { STATEMENT_NODE_LIST(V) \ EXPRESSION_NODE_LIST(V) +#ifdef WIN32 +#undef Yield +#endif + // Forward declarations class AstConstructionVisitor; template<class> class AstNodeFactory; @@ -349,6 +354,10 @@ class Expression: public AstNode { ASSERT(types != NULL && types->length() == 1); return types->at(0); } + virtual KeyedAccessStoreMode GetStoreMode() { + UNREACHABLE(); + return STANDARD_STORE; + } BailoutId id() const { return id_; } TypeFeedbackId test_id() const { return test_id_; } @@ -1481,7 +1490,9 @@ class Property: public Expression { void RecordTypeFeedback(TypeFeedbackOracle* oracle, Zone* zone); virtual bool IsMonomorphic() { return is_monomorphic_; } virtual SmallMapList* GetReceiverTypes() { return &receiver_types_; } - bool IsArrayLength() { return is_array_length_; } + virtual KeyedAccessStoreMode GetStoreMode() { + return STANDARD_STORE; + } bool IsUninitialized() { return is_uninitialized_; } TypeFeedbackId PropertyFeedbackId() { return reuse(id()); } @@ -1497,7 +1508,6 @@ class Property: public Expression { load_id_(GetNextId(isolate)), is_monomorphic_(false), is_uninitialized_(false), - is_array_length_(false), is_string_length_(false), is_string_access_(false), is_function_prototype_(false) { } @@ -1511,7 +1521,6 @@ class Property: public Expression { SmallMapList receiver_types_; bool is_monomorphic_ : 1; bool is_uninitialized_ : 1; - bool is_array_length_ : 1; bool is_string_length_ : 1; bool is_string_access_ : 1; bool is_function_prototype_ : 1; @@ -1773,6 +1782,9 @@ class CountOperation: public Expression { void RecordTypeFeedback(TypeFeedbackOracle* oracle, Zone* znoe); virtual bool IsMonomorphic() { return is_monomorphic_; } virtual SmallMapList* GetReceiverTypes() { return &receiver_types_; } + virtual KeyedAccessStoreMode GetStoreMode() { + return store_mode_; + } BailoutId AssignmentId() const { return assignment_id_; } @@ -1788,6 +1800,8 @@ class CountOperation: public Expression { : Expression(isolate), op_(op), is_prefix_(is_prefix), + is_monomorphic_(false), + store_mode_(STANDARD_STORE), expression_(expr), pos_(pos), assignment_id_(GetNextId(isolate)), @@ -1795,8 +1809,9 @@ class CountOperation: public Expression { private: Token::Value op_; - bool is_prefix_; - bool is_monomorphic_; + bool is_prefix_ : 1; + bool is_monomorphic_ : 1; + KeyedAccessStoreMode store_mode_: 4; Expression* expression_; int pos_; const BailoutId assignment_id_; @@ -1909,6 +1924,9 @@ class Assignment: public Expression { void RecordTypeFeedback(TypeFeedbackOracle* oracle, Zone* zone); virtual bool IsMonomorphic() { return is_monomorphic_; } virtual SmallMapList* GetReceiverTypes() { return &receiver_types_; } + virtual KeyedAccessStoreMode GetStoreMode() { + return store_mode_; + } protected: Assignment(Isolate* isolate, @@ -1934,11 +1952,37 @@ class Assignment: public Expression { BinaryOperation* binary_operation_; const BailoutId assignment_id_; - bool is_monomorphic_; + bool is_monomorphic_ : 1; + KeyedAccessStoreMode store_mode_ : 4; SmallMapList receiver_types_; }; +class Yield: public Expression { + public: + DECLARE_NODE_TYPE(Yield) + + Expression* expression() const { return expression_; } + bool is_delegating_yield() const { return is_delegating_yield_; } + virtual int position() const { return pos_; } + + protected: + Yield(Isolate* isolate, + Expression* expression, + bool is_delegating_yield, + int pos) + : Expression(isolate), + expression_(expression), + is_delegating_yield_(is_delegating_yield), + pos_(pos) { } + + private: + Expression* expression_; + bool is_delegating_yield_; + int pos_; +}; + + class Throw: public Expression { public: DECLARE_NODE_TYPE(Throw) @@ -1979,6 +2023,11 @@ class FunctionLiteral: public Expression { kNotParenthesized }; + enum IsGeneratorFlag { + kIsGenerator, + kNotGenerator + }; + DECLARE_NODE_TYPE(FunctionLiteral) Handle<String> name() const { return name_; } @@ -2039,6 +2088,10 @@ class FunctionLiteral: public Expression { bitfield_ = IsParenthesized::update(bitfield_, kIsParenthesized); } + bool is_generator() { + return IsGenerator::decode(bitfield_) == kIsGenerator; + } + int ast_node_count() { return ast_properties_.node_count(); } AstProperties::Flags* flags() { return ast_properties_.flags(); } void set_ast_properties(AstProperties* ast_properties) { @@ -2059,7 +2112,8 @@ class FunctionLiteral: public Expression { Type type, ParameterFlag has_duplicate_parameters, IsFunctionFlag is_function, - IsParenthesizedFlag is_parenthesized) + IsParenthesizedFlag is_parenthesized, + IsGeneratorFlag is_generator) : Expression(isolate), name_(name), scope_(scope), @@ -2079,7 +2133,8 @@ class FunctionLiteral: public Expression { Pretenure::encode(false) | HasDuplicateParameters::encode(has_duplicate_parameters) | IsFunction::encode(is_function) | - IsParenthesized::encode(is_parenthesized); + IsParenthesized::encode(is_parenthesized) | + IsGenerator::encode(is_generator); } private: @@ -2104,6 +2159,7 @@ class FunctionLiteral: public Expression { class HasDuplicateParameters: public BitField<ParameterFlag, 4, 1> {}; class IsFunction: public BitField<IsFunctionFlag, 5, 1> {}; class IsParenthesized: public BitField<IsParenthesizedFlag, 6, 1> {}; + class IsGenerator: public BitField<IsGeneratorFlag, 7, 1> {}; }; @@ -2902,6 +2958,12 @@ class AstNodeFactory BASE_EMBEDDED { VISIT_AND_RETURN(Assignment, assign) } + Yield* NewYield(Expression* expression, bool is_delegating_yield, int pos) { + Yield* yield = + new(zone_) Yield(isolate_, expression, is_delegating_yield, pos); + VISIT_AND_RETURN(Yield, yield) + } + Throw* NewThrow(Expression* exception, int pos) { Throw* t = new(zone_) Throw(isolate_, exception, pos); VISIT_AND_RETURN(Throw, t) @@ -2920,13 +2982,14 @@ class AstNodeFactory BASE_EMBEDDED { FunctionLiteral::ParameterFlag has_duplicate_parameters, FunctionLiteral::Type type, FunctionLiteral::IsFunctionFlag is_function, - FunctionLiteral::IsParenthesizedFlag is_parenthesized) { + FunctionLiteral::IsParenthesizedFlag is_parenthesized, + FunctionLiteral::IsGeneratorFlag is_generator) { FunctionLiteral* lit = new(zone_) FunctionLiteral( isolate_, name, scope, body, materialized_literal_count, expected_property_count, handler_count, has_only_simple_this_property_assignments, this_property_assignments, parameter_count, type, has_duplicate_parameters, is_function, - is_parenthesized); + is_parenthesized, is_generator); // Top-level literal doesn't count for the AST's properties. if (is_function == FunctionLiteral::kIsFunction) { visitor_.VisitFunctionLiteral(lit); diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index 58b2ad038..f57a1f6fd 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -303,9 +303,9 @@ Handle<Context> Bootstrapper::CreateEnvironment( v8::ExtensionConfiguration* extensions) { HandleScope scope(isolate_); Genesis genesis(isolate_, global_object, global_template, extensions); - Handle<Object> context(isolate_->global_handles()->Create(*genesis.result())); - Handle<Context> env = Handle<Context>::cast(context); - if (!env.is_null()) { + if (!genesis.result().is_null()) { + Handle<Object> ctx(isolate_->global_handles()->Create(*genesis.result())); + Handle<Context> env = Handle<Context>::cast(ctx); if (InstallExtensions(env, extensions)) { return env; } @@ -1280,7 +1280,17 @@ void Genesis::InitializeExperimentalGlobal() { Handle<JSObject> global = Handle<JSObject>(native_context()->global_object()); // TODO(mstarzinger): Move this into Genesis::InitializeGlobal once we no - // longer need to live behind a flag, so functions get added to the snapshot. + // longer need to live behind flags, so functions get added to the snapshot. + + if (FLAG_harmony_symbols) { + // --- S y m b o l --- + Handle<JSFunction> symbol_fun = + InstallFunction(global, "Symbol", JS_VALUE_TYPE, JSValue::kSize, + isolate()->initial_object_prototype(), + Builtins::kIllegal, true); + native_context()->set_symbol_function(*symbol_fun); + } + if (FLAG_harmony_collections) { { // -- S e t Handle<JSObject> prototype = @@ -1301,6 +1311,16 @@ void Genesis::InitializeExperimentalGlobal() { prototype, Builtins::kIllegal, true); } } + + if (FLAG_harmony_typed_arrays) { + { // -- A r r a y B u f f e r + Handle<JSObject> prototype = + factory()->NewJSObject(isolate()->object_function(), TENURED); + InstallFunction(global, "__ArrayBuffer", JS_ARRAY_BUFFER_TYPE, + JSArrayBuffer::kSize, prototype, + Builtins::kIllegal, true); + } + } } @@ -1436,9 +1456,6 @@ void Genesis::InstallNativeFunctions() { } void Genesis::InstallExperimentalNativeFunctions() { - if (FLAG_harmony_symbols) { - INSTALL_NATIVE(JSObject, "SymbolDelegate", symbol_delegate); - } if (FLAG_harmony_proxies) { INSTALL_NATIVE(JSFunction, "DerivedHasTrap", derived_has_trap); INSTALL_NATIVE(JSFunction, "DerivedGetTrap", derived_get_trap); @@ -1911,6 +1928,11 @@ bool Genesis::InstallExperimentalNatives() { "native object-observe.js") == 0) { if (!CompileExperimentalBuiltin(isolate(), i)) return false; } + if (FLAG_harmony_typed_arrays && + strcmp(ExperimentalNatives::GetScriptName(i).start(), + "native typedarray.js") == 0) { + if (!CompileExperimentalBuiltin(isolate(), i)) return false; + } } InstallExperimentalNativeFunctions(); diff --git a/deps/v8/src/code-stubs-hydrogen.cc b/deps/v8/src/code-stubs-hydrogen.cc index ae198bc24..ee903aef1 100644 --- a/deps/v8/src/code-stubs-hydrogen.cc +++ b/deps/v8/src/code-stubs-hydrogen.cc @@ -106,7 +106,8 @@ bool CodeStubGraphBuilderBase::BuildGraph() { Zone* zone = this->zone(); int param_count = descriptor_->register_param_count_; HEnvironment* start_environment = graph()->start_environment(); - HBasicBlock* next_block = CreateBasicBlock(start_environment); + HBasicBlock* next_block = + CreateBasicBlock(start_environment, BailoutId::StubEntry()); current_block()->Goto(next_block); next_block->SetJoinId(BailoutId::StubEntry()); set_current_block(next_block); @@ -128,7 +129,8 @@ bool CodeStubGraphBuilderBase::BuildGraph() { if (descriptor_->stack_parameter_count_ != NULL) { ASSERT(descriptor_->environment_length() == (param_count + 1)); stack_parameter_count = new(zone) HParameter(param_count, - HParameter::REGISTER_PARAMETER); + HParameter::REGISTER_PARAMETER, + Representation::Integer32()); // it's essential to bind this value to the environment in case of deopt start_environment->Bind(param_count, stack_parameter_count); AddInstruction(stack_parameter_count); @@ -146,13 +148,26 @@ bool CodeStubGraphBuilderBase::BuildGraph() { AddSimulate(BailoutId::StubEntry()); HValue* return_value = BuildCodeStub(); + + // We might have extra expressions to pop from the stack in addition to the + // arguments above + HInstruction* stack_pop_count = stack_parameter_count; + if (descriptor_->function_mode_ == JS_FUNCTION_STUB_MODE) { + HInstruction* amount = graph()->GetConstant1(); + stack_pop_count = AddInstruction( + HAdd::New(zone, context_, stack_parameter_count, amount)); + stack_pop_count->ChangeRepresentation(Representation::Integer32()); + stack_pop_count->ClearFlag(HValue::kCanOverflow); + } + HReturn* hreturn_instruction = new(zone) HReturn(return_value, context_, - stack_parameter_count); + stack_pop_count); current_block()->Finish(hreturn_instruction); return true; } + template <class Stub> class CodeStubGraphBuilder: public CodeStubGraphBuilderBase { public: @@ -165,6 +180,14 @@ class CodeStubGraphBuilder: public CodeStubGraphBuilderBase { }; +template <class Stub> +static Handle<Code> DoGenerateCode(Stub* stub) { + CodeStubGraphBuilder<Stub> builder(stub); + LChunk* chunk = OptimizeGraph(builder.CreateGraph()); + return chunk->Codegen(Code::COMPILED_STUB); +} + + template <> HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() { Zone* zone = this->zone(); @@ -176,7 +199,7 @@ HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() { NULL, FAST_ELEMENTS)); - CheckBuilder builder(this, BailoutId::StubEntry()); + CheckBuilder builder(this); builder.CheckNotUndefined(boilerplate); int size = JSObject::kHeaderSize + casted_stub()->length() * kPointerSize; @@ -216,9 +239,7 @@ HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() { Handle<Code> FastCloneShallowObjectStub::GenerateCode() { - CodeStubGraphBuilder<FastCloneShallowObjectStub> builder(this); - LChunk* chunk = OptimizeGraph(builder.CreateGraph()); - return chunk->Codegen(Code::COMPILED_STUB); + return DoGenerateCode(this); } @@ -227,16 +248,30 @@ HValue* CodeStubGraphBuilder<KeyedLoadFastElementStub>::BuildCodeStub() { HInstruction* load = BuildUncheckedMonomorphicElementAccess( GetParameter(0), GetParameter(1), NULL, NULL, casted_stub()->is_js_array(), casted_stub()->elements_kind(), - false, Representation::Tagged()); - AddInstruction(load); + false, STANDARD_STORE, Representation::Tagged()); return load; } Handle<Code> KeyedLoadFastElementStub::GenerateCode() { - CodeStubGraphBuilder<KeyedLoadFastElementStub> builder(this); - LChunk* chunk = OptimizeGraph(builder.CreateGraph()); - return chunk->Codegen(Code::COMPILED_STUB); + return DoGenerateCode(this); +} + + +template <> +HValue* CodeStubGraphBuilder<KeyedStoreFastElementStub>::BuildCodeStub() { + BuildUncheckedMonomorphicElementAccess( + GetParameter(0), GetParameter(1), GetParameter(2), NULL, + casted_stub()->is_js_array(), casted_stub()->elements_kind(), + true, casted_stub()->store_mode(), Representation::Tagged()); + AddSimulate(BailoutId::StubEntry(), REMOVABLE_SIMULATE); + + return GetParameter(2); +} + + +Handle<Code> KeyedStoreFastElementStub::GenerateCode() { + return DoGenerateCode(this); } @@ -252,31 +287,19 @@ HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() { AddInstruction(new(zone) HTrapAllocationMemento(js_array)); HInstruction* array_length = - AddInstruction(new(zone) HJSArrayLength(js_array, - js_array, - HType::Smi())); + AddInstruction(HLoadNamedField::NewArrayLength( + zone, js_array, js_array, HType::Smi())); - Heap* heap = isolate()->heap(); - const int kMinFreeNewSpaceAfterGC = - ((heap->InitialSemiSpaceSize() - sizeof(FixedArrayBase)) / 2) / - kDoubleSize; - - HConstant* max_alloc_size = - new(zone) HConstant(kMinFreeNewSpaceAfterGC, Representation::Integer32()); - AddInstruction(max_alloc_size); - // Since we're forcing Integer32 representation for this HBoundsCheck, - // there's no need to Smi-check the index. - AddInstruction( - new(zone) HBoundsCheck(array_length, max_alloc_size, - DONT_ALLOW_SMI_KEY, Representation::Integer32())); + ElementsKind to_kind = casted_stub()->to_kind(); + BuildNewSpaceArrayCheck(array_length, to_kind); - IfBuilder if_builder(this, BailoutId::StubEntry()); + IfBuilder if_builder(this); - if_builder.BeginTrue(array_length, graph()->GetConstant0(), Token::EQ); + if_builder.BeginIf(array_length, graph()->GetConstant0(), Token::EQ); // Nothing to do, just change the map. - if_builder.BeginFalse(); + if_builder.BeginElse(); HInstruction* elements = AddInstruction(new(zone) HLoadElements(js_array, js_array)); @@ -284,37 +307,14 @@ HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() { HInstruction* elements_length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); - ElementsKind to_kind = casted_stub()->to_kind(); HValue* new_elements = BuildAllocateElements(context(), to_kind, elements_length); - // Fast elements kinds need to be initialized in case statements below cause a - // garbage collection. - Factory* factory = isolate()->factory(); - - ASSERT(!IsFastSmiElementsKind(to_kind)); - double nan_double = FixedDoubleArray::hole_nan_as_double(); - HValue* hole = IsFastObjectElementsKind(to_kind) - ? AddInstruction(new(zone) HConstant(factory->the_hole_value(), - Representation::Tagged())) - : AddInstruction(new(zone) HConstant(nan_double, - Representation::Double())); - - LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement, - BailoutId::StubEntry()); - - HValue* zero = graph()->GetConstant0(); - HValue* start = IsFastElementsKind(to_kind) ? zero : array_length; - HValue* key = builder.BeginBody(start, elements_length, Token::LT); - - AddInstruction(new(zone) HStoreKeyed(new_elements, key, hole, to_kind)); - AddSimulate(BailoutId::StubEntry(), REMOVABLE_SIMULATE); - - builder.EndBody(); - BuildCopyElements(context(), elements, casted_stub()->from_kind(), new_elements, - to_kind, array_length); + to_kind, array_length, elements_length); + + Factory* factory = isolate()->factory(); AddInstruction(new(zone) HStoreNamedField(js_array, factory->elements_field_string(), @@ -331,6 +331,11 @@ HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() { } +Handle<Code> TransitionElementsKindStub::GenerateCode() { + return DoGenerateCode(this); +} + + template <> HValue* CodeStubGraphBuilder<ArrayNoArgumentConstructorStub>::BuildCodeStub() { HInstruction* deopt = new(zone()) HSoftDeoptimize(); @@ -341,9 +346,7 @@ HValue* CodeStubGraphBuilder<ArrayNoArgumentConstructorStub>::BuildCodeStub() { Handle<Code> ArrayNoArgumentConstructorStub::GenerateCode() { - CodeStubGraphBuilder<ArrayNoArgumentConstructorStub> builder(this); - LChunk* chunk = OptimizeGraph(builder.CreateGraph()); - return chunk->Codegen(Code::COMPILED_STUB); + return DoGenerateCode(this); } @@ -357,17 +360,8 @@ HValue* CodeStubGraphBuilder<ArraySingleArgumentConstructorStub>:: } -Handle<Code> TransitionElementsKindStub::GenerateCode() { - CodeStubGraphBuilder<TransitionElementsKindStub> builder(this); - LChunk* chunk = OptimizeGraph(builder.CreateGraph()); - return chunk->Codegen(Code::COMPILED_STUB); -} - - Handle<Code> ArraySingleArgumentConstructorStub::GenerateCode() { - CodeStubGraphBuilder<ArraySingleArgumentConstructorStub> builder(this); - LChunk* chunk = OptimizeGraph(builder.CreateGraph()); - return chunk->Codegen(Code::COMPILED_STUB); + return DoGenerateCode(this); } @@ -381,9 +375,7 @@ HValue* CodeStubGraphBuilder<ArrayNArgumentsConstructorStub>::BuildCodeStub() { Handle<Code> ArrayNArgumentsConstructorStub::GenerateCode() { - CodeStubGraphBuilder<ArrayNArgumentsConstructorStub> builder(this); - LChunk* chunk = OptimizeGraph(builder.CreateGraph()); - return chunk->Codegen(Code::COMPILED_STUB); + return DoGenerateCode(this); } } } // namespace v8::internal diff --git a/deps/v8/src/code-stubs.cc b/deps/v8/src/code-stubs.cc index 95bc1e99c..eff0f7f1c 100644 --- a/deps/v8/src/code-stubs.cc +++ b/deps/v8/src/code-stubs.cc @@ -510,6 +510,7 @@ void ToBooleanStub::Types::Print(StringStream* stream) const { if (Contains(SMI)) stream->Add("Smi"); if (Contains(SPEC_OBJECT)) stream->Add("SpecObject"); if (Contains(STRING)) stream->Add("String"); + if (Contains(SYMBOL)) stream->Add("Symbol"); if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber"); } @@ -549,6 +550,9 @@ bool ToBooleanStub::Types::Record(Handle<Object> object) { Add(STRING); return !object->IsUndetectableObject() && String::cast(*object)->length() != 0; + } else if (object->IsSymbol()) { + Add(SYMBOL); + return true; } else if (object->IsHeapNumber()) { ASSERT(!object->IsUndetectableObject()); Add(HEAP_NUMBER); @@ -565,6 +569,7 @@ bool ToBooleanStub::Types::Record(Handle<Object> object) { bool ToBooleanStub::Types::NeedsMap() const { return Contains(ToBooleanStub::SPEC_OBJECT) || Contains(ToBooleanStub::STRING) + || Contains(ToBooleanStub::SYMBOL) || Contains(ToBooleanStub::HEAP_NUMBER); } @@ -614,10 +619,8 @@ void ElementsTransitionAndStoreStub::Generate(MacroAssembler* masm) { void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) { - int i = 0; - for (; i <= StubFailureTrampolineStub::kMaxExtraExpressionStackCount; ++i) { - StubFailureTrampolineStub(i).GetCode(isolate); - } + StubFailureTrampolineStub(NOT_JS_FUNCTION_STUB_MODE).GetCode(isolate); + StubFailureTrampolineStub(JS_FUNCTION_STUB_MODE).GetCode(isolate); } diff --git a/deps/v8/src/code-stubs.h b/deps/v8/src/code-stubs.h index e91b24157..99ff5154e 100644 --- a/deps/v8/src/code-stubs.h +++ b/deps/v8/src/code-stubs.h @@ -47,7 +47,6 @@ namespace internal { V(Compare) \ V(CompareIC) \ V(MathPow) \ - V(ArrayLength) \ V(StringLength) \ V(FunctionPrototype) \ V(StoreArrayLength) \ @@ -259,15 +258,17 @@ class PlatformCodeStub : public CodeStub { }; +enum StubFunctionMode { NOT_JS_FUNCTION_STUB_MODE, JS_FUNCTION_STUB_MODE }; + struct CodeStubInterfaceDescriptor { CodeStubInterfaceDescriptor() : register_param_count_(-1), stack_parameter_count_(NULL), - extra_expression_stack_count_(0), + function_mode_(NOT_JS_FUNCTION_STUB_MODE), register_params_(NULL) { } int register_param_count_; const Register* stack_parameter_count_; - int extra_expression_stack_count_; + StubFunctionMode function_mode_; Register* register_params_; Address deoptimization_handler_; @@ -597,16 +598,6 @@ class ICStub: public PlatformCodeStub { }; -class ArrayLengthStub: public ICStub { - public: - explicit ArrayLengthStub(Code::Kind kind) : ICStub(kind) { } - virtual void Generate(MacroAssembler* masm); - - private: - virtual CodeStub::Major MajorKey() { return ArrayLength; } -}; - - class FunctionPrototypeStub: public ICStub { public: explicit FunctionPrototypeStub(Code::Kind kind) : ICStub(kind) { } @@ -1312,6 +1303,47 @@ class KeyedLoadFastElementStub : public HydrogenCodeStub { }; +class KeyedStoreFastElementStub : public HydrogenCodeStub { + public: + KeyedStoreFastElementStub(bool is_js_array, + ElementsKind elements_kind, + KeyedAccessStoreMode mode) { + bit_field_ = ElementsKindBits::encode(elements_kind) | + IsJSArrayBits::encode(is_js_array) | + StoreModeBits::encode(mode); + } + + Major MajorKey() { return KeyedStoreElement; } + int MinorKey() { return bit_field_; } + + bool is_js_array() const { + return IsJSArrayBits::decode(bit_field_); + } + + ElementsKind elements_kind() const { + return ElementsKindBits::decode(bit_field_); + } + + KeyedAccessStoreMode store_mode() const { + return StoreModeBits::decode(bit_field_); + } + + virtual Handle<Code> GenerateCode(); + + virtual void InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor); + + private: + class ElementsKindBits: public BitField<ElementsKind, 0, 8> {}; + class StoreModeBits: public BitField<KeyedAccessStoreMode, 8, 4> {}; + class IsJSArrayBits: public BitField<bool, 12, 1> {}; + uint32_t bit_field_; + + DISALLOW_COPY_AND_ASSIGN(KeyedStoreFastElementStub); +}; + + class TransitionElementsKindStub : public HydrogenCodeStub { public: TransitionElementsKindStub(ElementsKind from_kind, @@ -1447,6 +1479,7 @@ class ToBooleanStub: public PlatformCodeStub { SMI, SPEC_OBJECT, STRING, + SYMBOL, HEAP_NUMBER, NUMBER_OF_TYPES }; @@ -1570,10 +1603,8 @@ class StoreArrayLiteralElementStub : public PlatformCodeStub { class StubFailureTrampolineStub : public PlatformCodeStub { public: - static const int kMaxExtraExpressionStackCount = 1; - - explicit StubFailureTrampolineStub(int extra_expression_stack_count) - : extra_expression_stack_count_(extra_expression_stack_count) {} + explicit StubFailureTrampolineStub(StubFunctionMode function_mode) + : function_mode_(function_mode) {} virtual bool IsPregenerated() { return true; } @@ -1581,11 +1612,11 @@ class StubFailureTrampolineStub : public PlatformCodeStub { private: Major MajorKey() { return StubFailureTrampoline; } - int MinorKey() { return extra_expression_stack_count_; } + int MinorKey() { return static_cast<int>(function_mode_); } void Generate(MacroAssembler* masm); - int extra_expression_stack_count_; + StubFunctionMode function_mode_; DISALLOW_COPY_AND_ASSIGN(StubFailureTrampolineStub); }; diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index 2c4dae5d4..6f9b901d9 100644 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -1121,6 +1121,7 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info, function_info->set_dont_optimize(lit->flags()->Contains(kDontOptimize)); function_info->set_dont_inline(lit->flags()->Contains(kDontInline)); function_info->set_dont_cache(lit->flags()->Contains(kDontCache)); + function_info->set_is_generator(lit->is_generator()); } diff --git a/deps/v8/src/contexts.h b/deps/v8/src/contexts.h index cd7ed6adc..a0ba2f7eb 100644 --- a/deps/v8/src/contexts.h +++ b/deps/v8/src/contexts.h @@ -103,6 +103,7 @@ enum BindingFlags { V(NUMBER_FUNCTION_INDEX, JSFunction, number_function) \ V(STRING_FUNCTION_INDEX, JSFunction, string_function) \ V(STRING_FUNCTION_PROTOTYPE_MAP_INDEX, Map, string_function_prototype_map) \ + V(SYMBOL_FUNCTION_INDEX, JSFunction, symbol_function) \ V(OBJECT_FUNCTION_INDEX, JSFunction, object_function) \ V(INTERNAL_ARRAY_FUNCTION_INDEX, JSFunction, internal_array_function) \ V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \ @@ -156,7 +157,6 @@ enum BindingFlags { V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \ V(ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX, Object, \ error_message_for_code_gen_from_strings) \ - V(SYMBOL_DELEGATE_INDEX, JSObject, symbol_delegate) \ V(TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX, JSFunction, \ to_complete_property_descriptor) \ V(DERIVED_HAS_TRAP_INDEX, JSFunction, derived_has_trap) \ @@ -251,6 +251,7 @@ class Context: public FixedArray { NUMBER_FUNCTION_INDEX, STRING_FUNCTION_INDEX, STRING_FUNCTION_PROTOTYPE_MAP_INDEX, + SYMBOL_FUNCTION_INDEX, OBJECT_FUNCTION_INDEX, INTERNAL_ARRAY_FUNCTION_INDEX, ARRAY_FUNCTION_INDEX, @@ -287,7 +288,6 @@ class Context: public FixedArray { EMBEDDER_DATA_INDEX, ALLOW_CODE_GEN_FROM_STRINGS_INDEX, ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX, - SYMBOL_DELEGATE_INDEX, TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX, DERIVED_HAS_TRAP_INDEX, DERIVED_GET_TRAP_INDEX, diff --git a/deps/v8/src/d8.cc b/deps/v8/src/d8.cc index 805a0cf1a..b57e3907c 100644 --- a/deps/v8/src/d8.cc +++ b/deps/v8/src/d8.cc @@ -227,11 +227,13 @@ bool Shell::ExecuteString(Isolate* isolate, } #if !defined(V8_SHARED) } else { + v8::TryCatch try_catch; Context::Scope context_scope(utility_context_); Handle<Object> global = utility_context_->Global(); Handle<Value> fun = global->Get(String::New("Stringify")); Handle<Value> argv[1] = { result }; Handle<Value> s = Handle<Function>::Cast(fun)->Call(global, 1, argv); + if (try_catch.HasCaught()) return true; v8::String::Utf8Value str(s); fwrite(*str, sizeof(**str), str.length(), stdout); printf("\n"); @@ -905,12 +907,6 @@ Handle<Value> Shell::Uint8ClampedArray(const Arguments& args) { } -Handle<Value> Shell::Yield(const Arguments& args) { - v8::Unlocker unlocker(args.GetIsolate()); - return Undefined(args.GetIsolate()); -} - - Handle<Value> Shell::Quit(const Arguments& args) { int exit_code = args[0]->Int32Value(); OnExit(); diff --git a/deps/v8/src/d8.h b/deps/v8/src/d8.h index 621ac7409..2789c0763 100644 --- a/deps/v8/src/d8.h +++ b/deps/v8/src/d8.h @@ -298,13 +298,8 @@ class Shell : public i::AllStatic { #endif // ENABLE_DEBUGGER_SUPPORT #endif // V8_SHARED -#ifdef WIN32 -#undef Yield -#endif - static Handle<Value> Print(const Arguments& args); static Handle<Value> Write(const Arguments& args); - static Handle<Value> Yield(const Arguments& args); static Handle<Value> Quit(const Arguments& args); static Handle<Value> Version(const Arguments& args); static Handle<Value> EnableProfiler(const Arguments& args); diff --git a/deps/v8/src/d8.js b/deps/v8/src/d8.js index 1ff0ce898..df1046133 100644 --- a/deps/v8/src/d8.js +++ b/deps/v8/src/d8.js @@ -2214,7 +2214,8 @@ function Stringify(x, depth) { return x.toString(); case "string": return "\"" + x.toString() + "\""; - // TODO(rossberg): add symbol case + case "symbol": + return "Symbol(" + (x.name ? Stringify(x.name, depth) : "") + ")" case "object": if (x === null) return "null"; if (x.constructor && x.constructor.name === "Array") { diff --git a/deps/v8/src/debug.cc b/deps/v8/src/debug.cc index 7a876e71f..91af9ccc1 100644 --- a/deps/v8/src/debug.cc +++ b/deps/v8/src/debug.cc @@ -3761,8 +3761,8 @@ void LockingCommandMessageQueue::Clear() { MessageDispatchHelperThread::MessageDispatchHelperThread(Isolate* isolate) : Thread("v8:MsgDispHelpr"), - sem_(OS::CreateSemaphore(0)), mutex_(OS::CreateMutex()), - already_signalled_(false) { + isolate_(isolate), sem_(OS::CreateSemaphore(0)), + mutex_(OS::CreateMutex()), already_signalled_(false) { } @@ -3785,7 +3785,6 @@ void MessageDispatchHelperThread::Schedule() { void MessageDispatchHelperThread::Run() { - Isolate* isolate = Isolate::Current(); while (true) { sem_->Wait(); { @@ -3793,8 +3792,8 @@ void MessageDispatchHelperThread::Run() { already_signalled_ = false; } { - Locker locker(reinterpret_cast<v8::Isolate*>(isolate)); - isolate->debugger()->CallMessageDispatchHandler(); + Locker locker(reinterpret_cast<v8::Isolate*>(isolate_)); + isolate_->debugger()->CallMessageDispatchHandler(); } } } diff --git a/deps/v8/src/debug.h b/deps/v8/src/debug.h index c7f06815b..459073fe0 100644 --- a/deps/v8/src/debug.h +++ b/deps/v8/src/debug.h @@ -1041,6 +1041,7 @@ class MessageDispatchHelperThread: public Thread { private: void Run(); + Isolate* isolate_; Semaphore* const sem_; Mutex* const mutex_; bool already_signalled_; diff --git a/deps/v8/src/deoptimizer.cc b/deps/v8/src/deoptimizer.cc index f03025cbf..601faf723 100644 --- a/deps/v8/src/deoptimizer.cc +++ b/deps/v8/src/deoptimizer.cc @@ -1280,29 +1280,37 @@ void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator, } intptr_t caller_arg_count = 0; - if (descriptor->stack_parameter_count_ != NULL) { - caller_arg_count = - input_->GetRegister(descriptor->stack_parameter_count_->code()); - } + bool arg_count_known = descriptor->stack_parameter_count_ == NULL; // Build the Arguments object for the caller's parameters and a pointer to it. output_frame_offset -= kPointerSize; - value = frame_ptr + StandardFrameConstants::kCallerSPOffset + - (caller_arg_count - 1) * kPointerSize; - output_frame->SetFrameSlot(output_frame_offset, value); + int args_arguments_offset = output_frame_offset; + intptr_t the_hole = reinterpret_cast<intptr_t>( + isolate_->heap()->the_hole_value()); + if (arg_count_known) { + value = frame_ptr + StandardFrameConstants::kCallerSPOffset + + (caller_arg_count - 1) * kPointerSize; + } else { + value = the_hole; + } + + output_frame->SetFrameSlot(args_arguments_offset, value); if (trace_) { PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" - V8PRIxPTR " ; args.arguments\n", - top_address + output_frame_offset, output_frame_offset, value); + V8PRIxPTR " ; args.arguments %s\n", + top_address + args_arguments_offset, args_arguments_offset, value, + arg_count_known ? "" : "(the hole)"); } output_frame_offset -= kPointerSize; - value = caller_arg_count; - output_frame->SetFrameSlot(output_frame_offset, value); + int length_frame_offset = output_frame_offset; + value = arg_count_known ? caller_arg_count : the_hole; + output_frame->SetFrameSlot(length_frame_offset, value); if (trace_) { PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" - V8PRIxPTR " ; args.length\n", - top_address + output_frame_offset, output_frame_offset, value); + V8PRIxPTR " ; args.length %s\n", + top_address + length_frame_offset, length_frame_offset, value, + arg_count_known ? "" : "(the hole)"); } output_frame_offset -= kPointerSize; @@ -1321,6 +1329,20 @@ void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator, DoTranslateCommand(iterator, 0, output_frame_offset); } + if (!arg_count_known) { + DoTranslateCommand(iterator, 0, length_frame_offset, + TRANSLATED_VALUE_IS_NATIVE); + caller_arg_count = output_frame->GetFrameSlot(length_frame_offset); + value = frame_ptr + StandardFrameConstants::kCallerSPOffset + + (caller_arg_count - 1) * kPointerSize; + output_frame->SetFrameSlot(args_arguments_offset, value); + if (trace_) { + PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" + V8PRIxPTR " ; args.arguments\n", + top_address + args_arguments_offset, args_arguments_offset, value); + } + } + ASSERT(0 == output_frame_offset); // Copy the double registers from the input into the output frame. @@ -1331,8 +1353,9 @@ void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator, // Compute this frame's PC, state, and continuation. Code* trampoline = NULL; - int extra = descriptor->extra_expression_stack_count_; - StubFailureTrampolineStub(extra).FindCodeInCache(&trampoline, isolate_); + StubFunctionMode function_mode = descriptor->function_mode_; + StubFailureTrampolineStub(function_mode).FindCodeInCache(&trampoline, + isolate_); ASSERT(trampoline != NULL); output_frame->SetPc(reinterpret_cast<intptr_t>( trampoline->instruction_start())); @@ -1476,12 +1499,25 @@ void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame( #endif +static const char* TraceValueType(bool is_smi, bool is_native) { + if (is_native) { + return "native"; + } else if (is_smi) { + return "smi"; + } + + return "heap number"; +} + + void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, - int frame_index, - unsigned output_offset) { + int frame_index, + unsigned output_offset, + DeoptimizerTranslatedValueType value_type) { disasm::NameConverter converter; // A GC-safe temporary placeholder that we can put in the output frame. const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0)); + bool is_native = value_type == TRANSLATED_VALUE_IS_NATIVE; // Ignore commands marked as duplicate and act on the first non-duplicate. Translation::Opcode opcode = @@ -1524,7 +1560,9 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, case Translation::INT32_REGISTER: { int input_reg = iterator->Next(); intptr_t value = input_->GetRegister(input_reg); - bool is_smi = Smi::IsValid(value); + bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) && + Smi::IsValid(value); + if (trace_) { PrintF( " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n", @@ -1532,15 +1570,18 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, output_offset, value, converter.NameOfCPURegister(input_reg), - is_smi ? "smi" : "heap number"); + TraceValueType(is_smi, is_native)); } if (is_smi) { intptr_t tagged_value = reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value))); output_[frame_index]->SetFrameSlot(output_offset, tagged_value); + } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) { + output_[frame_index]->SetFrameSlot(output_offset, value); } else { // We save the untagged value on the side and store a GC-safe // temporary placeholder in the frame. + ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED); AddDoubleValue(output_[frame_index]->GetTop() + output_offset, static_cast<double>(static_cast<int32_t>(value))); output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder); @@ -1551,7 +1592,8 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, case Translation::UINT32_REGISTER: { int input_reg = iterator->Next(); uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg)); - bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue)); + bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) && + (value <= static_cast<uintptr_t>(Smi::kMaxValue)); if (trace_) { PrintF( " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIuPTR @@ -1560,15 +1602,18 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, output_offset, value, converter.NameOfCPURegister(input_reg), - is_smi ? "smi" : "heap number"); + TraceValueType(is_smi, is_native)); } if (is_smi) { intptr_t tagged_value = reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value))); output_[frame_index]->SetFrameSlot(output_offset, tagged_value); + } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) { + output_[frame_index]->SetFrameSlot(output_offset, value); } else { // We save the untagged value on the side and store a GC-safe // temporary placeholder in the frame. + ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED); AddDoubleValue(output_[frame_index]->GetTop() + output_offset, static_cast<double>(static_cast<uint32_t>(value))); output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder); @@ -1617,7 +1662,8 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index); intptr_t value = input_->GetFrameSlot(input_offset); - bool is_smi = Smi::IsValid(value); + bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) && + Smi::IsValid(value); if (trace_) { PrintF(" 0x%08" V8PRIxPTR ": ", output_[frame_index]->GetTop() + output_offset); @@ -1625,15 +1671,18 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, output_offset, value, input_offset, - is_smi ? "smi" : "heap number"); + TraceValueType(is_smi, is_native)); } if (is_smi) { intptr_t tagged_value = reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value))); output_[frame_index]->SetFrameSlot(output_offset, tagged_value); + } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) { + output_[frame_index]->SetFrameSlot(output_offset, value); } else { // We save the untagged value on the side and store a GC-safe // temporary placeholder in the frame. + ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED); AddDoubleValue(output_[frame_index]->GetTop() + output_offset, static_cast<double>(static_cast<int32_t>(value))); output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder); @@ -1647,7 +1696,8 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, input_->GetOffsetFromSlotIndex(input_slot_index); uintptr_t value = static_cast<uintptr_t>(input_->GetFrameSlot(input_offset)); - bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue)); + bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) && + (value <= static_cast<uintptr_t>(Smi::kMaxValue)); if (trace_) { PrintF(" 0x%08" V8PRIxPTR ": ", output_[frame_index]->GetTop() + output_offset); @@ -1655,15 +1705,18 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, output_offset, value, input_offset, - is_smi ? "smi" : "heap number"); + TraceValueType(is_smi, is_native)); } if (is_smi) { intptr_t tagged_value = reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value))); output_[frame_index]->SetFrameSlot(output_offset, tagged_value); + } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) { + output_[frame_index]->SetFrameSlot(output_offset, value); } else { // We save the untagged value on the side and store a GC-safe // temporary placeholder in the frame. + ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED); AddDoubleValue(output_[frame_index]->GetTop() + output_offset, static_cast<double>(static_cast<uint32_t>(value))); output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder); @@ -2130,7 +2183,8 @@ void Deoptimizer::EnsureCodeForDeoptimizationEntry(Isolate* isolate, ASSERT(static_cast<int>(Deoptimizer::GetMaxDeoptTableSize()) >= desc.instr_size); chunk->CommitArea(desc.instr_size); - memcpy(chunk->area_start(), desc.buffer, desc.instr_size); + CopyBytes(chunk->area_start(), desc.buffer, + static_cast<size_t>(desc.instr_size)); CPU::FlushICache(chunk->area_start(), desc.instr_size); if (type == EAGER) { diff --git a/deps/v8/src/deoptimizer.h b/deps/v8/src/deoptimizer.h index db0cc0bde..895ed6690 100644 --- a/deps/v8/src/deoptimizer.h +++ b/deps/v8/src/deoptimizer.h @@ -356,9 +356,17 @@ class Deoptimizer : public Malloced { bool is_setter_stub_frame); void DoComputeCompiledStubFrame(TranslationIterator* iterator, int frame_index); + + enum DeoptimizerTranslatedValueType { + TRANSLATED_VALUE_IS_NATIVE, + TRANSLATED_VALUE_IS_TAGGED + }; + void DoTranslateCommand(TranslationIterator* iterator, - int frame_index, - unsigned output_offset); + int frame_index, + unsigned output_offset, + DeoptimizerTranslatedValueType value_type = TRANSLATED_VALUE_IS_TAGGED); + // Translate a command for OSR. Updates the input offset to be used for // the next command. Returns false if translation of the command failed // (e.g., a number conversion failed) and may or may not have updated the diff --git a/deps/v8/src/elements-kind.h b/deps/v8/src/elements-kind.h index cb3bb9c9e..da151924b 100644 --- a/deps/v8/src/elements-kind.h +++ b/deps/v8/src/elements-kind.h @@ -110,10 +110,15 @@ inline bool IsFastDoubleElementsKind(ElementsKind kind) { } +inline bool IsExternalFloatOrDoubleElementsKind(ElementsKind kind) { + return kind == EXTERNAL_DOUBLE_ELEMENTS || + kind == EXTERNAL_FLOAT_ELEMENTS; +} + + inline bool IsDoubleOrFloatElementsKind(ElementsKind kind) { return IsFastDoubleElementsKind(kind) || - kind == EXTERNAL_DOUBLE_ELEMENTS || - kind == EXTERNAL_FLOAT_ELEMENTS; + IsExternalFloatOrDoubleElementsKind(kind); } diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h index c4b560bc8..ea72168b7 100644 --- a/deps/v8/src/flag-definitions.h +++ b/deps/v8/src/flag-definitions.h @@ -148,6 +148,9 @@ DEFINE_bool(harmony_collections, false, "enable harmony collections (sets, maps, and weak maps)") DEFINE_bool(harmony_observation, false, "enable harmony object observation (implies harmony collections") +DEFINE_bool(harmony_typed_arrays, false, + "enable harmony typed arrays") +DEFINE_bool(harmony_generators, false, "enable harmony generators") DEFINE_bool(harmony, false, "enable all harmony features (except typeof)") DEFINE_implication(harmony, harmony_scoping) DEFINE_implication(harmony, harmony_modules) @@ -155,14 +158,18 @@ DEFINE_implication(harmony, harmony_symbols) DEFINE_implication(harmony, harmony_proxies) DEFINE_implication(harmony, harmony_collections) DEFINE_implication(harmony, harmony_observation) +DEFINE_implication(harmony, harmony_generators) DEFINE_implication(harmony_modules, harmony_scoping) DEFINE_implication(harmony_observation, harmony_collections) +DEFINE_implication(harmony, harmony_typed_arrays) // Flags for experimental implementation features. DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes") DEFINE_bool(smi_only_arrays, true, "tracks arrays with only smi values") DEFINE_bool(compiled_transitions, false, "use optimizing compiler to " "generate array elements transition stubs") +DEFINE_bool(compiled_keyed_stores, false, "use optimizing compiler to " + "generate keyed store stubs") DEFINE_bool(clever_optimizations, true, "Optimize object size, Array shift, DOM strings and string +") @@ -424,7 +431,7 @@ DEFINE_bool(trace_external_memory, false, "it is adjusted.") DEFINE_bool(collect_maps, true, "garbage collect maps from which no objects can be reached") -DEFINE_bool(weak_embedded_maps_in_optimized_code, true, +DEFINE_bool(weak_embedded_maps_in_optimized_code, false, "make maps embedded in optimized code weak") DEFINE_bool(flush_code, true, "flush code that we expect not to use again (during full gc)") diff --git a/deps/v8/src/frames.cc b/deps/v8/src/frames.cc index ed407e796..aaf8c79e2 100644 --- a/deps/v8/src/frames.cc +++ b/deps/v8/src/frames.cc @@ -1311,18 +1311,19 @@ Address StubFailureTrampolineFrame::GetCallerStackPointer() const { Code* StubFailureTrampolineFrame::unchecked_code() const { - int i = 0; - for (; i <= StubFailureTrampolineStub::kMaxExtraExpressionStackCount; ++i) { - Code* trampoline; - StubFailureTrampolineStub(i).FindCodeInCache(&trampoline, isolate()); - ASSERT(trampoline != NULL); - Address current_pc = pc(); - Address code_start = trampoline->instruction_start(); - Address code_end = code_start + trampoline->instruction_size(); - if (code_start <= current_pc && current_pc < code_end) { - return trampoline; - } + Code* trampoline; + StubFailureTrampolineStub(NOT_JS_FUNCTION_STUB_MODE). + FindCodeInCache(&trampoline, isolate()); + if (trampoline->contains(pc())) { + return trampoline; } + + StubFailureTrampolineStub(JS_FUNCTION_STUB_MODE). + FindCodeInCache(&trampoline, isolate()); + if (trampoline->contains(pc())) { + return trampoline; + } + UNREACHABLE(); return NULL; } diff --git a/deps/v8/src/full-codegen.cc b/deps/v8/src/full-codegen.cc index cb6f228a1..1c6a0b91b 100644 --- a/deps/v8/src/full-codegen.cc +++ b/deps/v8/src/full-codegen.cc @@ -232,6 +232,12 @@ void BreakableStatementChecker::VisitAssignment(Assignment* expr) { } +void BreakableStatementChecker::VisitYield(Yield* expr) { + // Yield is breakable if the expression is. + Visit(expr->expression()); +} + + void BreakableStatementChecker::VisitThrow(Throw* expr) { // Throw is breakable if the expression is. Visit(expr->exception()); @@ -1538,6 +1544,28 @@ void FullCodeGenerator::VisitSharedFunctionInfoLiteral( } +void FullCodeGenerator::VisitYield(Yield* expr) { + if (expr->is_delegating_yield()) + UNIMPLEMENTED(); + + Comment cmnt(masm_, "[ Yield"); + VisitForAccumulatorValue(expr->expression()); + // TODO(wingo): Assert that the operand stack depth is 0, at least while + // general yield expressions are unimplemented. + + // TODO(wingo): What follows is as in VisitReturnStatement. Replace it with a + // call to a builtin that will resume the generator. + NestedStatement* current = nesting_stack_; + int stack_depth = 0; + int context_length = 0; + while (current != NULL) { + current = current->Exit(&stack_depth, &context_length); + } + __ Drop(stack_depth); + EmitReturnSequence(); +} + + void FullCodeGenerator::VisitThrow(Throw* expr) { Comment cmnt(masm_, "[ Throw"); VisitForStackValue(expr->exception()); diff --git a/deps/v8/src/gdb-jit.cc b/deps/v8/src/gdb-jit.cc index dde6bbdaa..cf8ca2d4d 100644 --- a/deps/v8/src/gdb-jit.cc +++ b/deps/v8/src/gdb-jit.cc @@ -187,7 +187,7 @@ class Writer BASE_EMBEDDED { byte* buffer_; }; -class StringTable; +class ELFStringTable; template<typename THeader> class DebugSectionBase : public ZoneObject { @@ -338,7 +338,7 @@ class ELFSection : public DebugSectionBase<ELFSectionHeader> { virtual ~ELFSection() { } - void PopulateHeader(Writer::Slot<Header> header, StringTable* strtab); + void PopulateHeader(Writer::Slot<Header> header, ELFStringTable* strtab); virtual void WriteBody(Writer::Slot<Header> header, Writer* w) { uintptr_t start = w->position(); @@ -438,9 +438,9 @@ class FullHeaderELFSection : public ELFSection { }; -class StringTable : public ELFSection { +class ELFStringTable : public ELFSection { public: - explicit StringTable(const char* name) + explicit ELFStringTable(const char* name) : ELFSection(name, TYPE_STRTAB, 1), writer_(NULL), offset_(0), size_(0) { } @@ -488,7 +488,7 @@ class StringTable : public ELFSection { void ELFSection::PopulateHeader(Writer::Slot<ELFSection::Header> header, - StringTable* strtab) { + ELFStringTable* strtab) { header->name = strtab->Add(name_); header->type = type_; header->alignment = align_; @@ -631,7 +631,7 @@ class ELF BASE_EMBEDDED { public: ELF(Zone* zone) : sections_(6, zone) { sections_.Add(new(zone) ELFSection("", ELFSection::TYPE_NULL, 0), zone); - sections_.Add(new(zone) StringTable(".shstrtab"), zone); + sections_.Add(new(zone) ELFStringTable(".shstrtab"), zone); } void Write(Writer* w) { @@ -718,7 +718,7 @@ class ELF BASE_EMBEDDED { w->CreateSlotsHere<ELFSection::Header>(sections_.length()); // String table for section table is the first section. - StringTable* strtab = static_cast<StringTable*>(SectionAt(1)); + ELFStringTable* strtab = static_cast<ELFStringTable*>(SectionAt(1)); strtab->AttachWriter(w); for (int i = 0, length = sections_.length(); i < length; @@ -832,7 +832,7 @@ class ELFSymbol BASE_EMBEDDED { }; #endif - void Write(Writer::Slot<SerializedLayout> s, StringTable* t) { + void Write(Writer::Slot<SerializedLayout> s, ELFStringTable* t) { // Convert symbol names from strings to indexes in the string table. s->name = t->Add(name); s->value = value; @@ -871,8 +871,8 @@ class ELFSymbolTable : public ELFSection { header->size = w->position() - header->offset; // String table for this symbol table should follow it in the section table. - StringTable* strtab = - static_cast<StringTable*>(w->debug_object()->SectionAt(index() + 1)); + ELFStringTable* strtab = + static_cast<ELFStringTable*>(w->debug_object()->SectionAt(index() + 1)); strtab->AttachWriter(w); symbols.at(0).set(ELFSymbol::SerializedLayout(0, 0, @@ -905,7 +905,7 @@ class ELFSymbolTable : public ELFSection { private: void WriteSymbolsList(const ZoneList<ELFSymbol>* src, Writer::Slot<ELFSymbol::SerializedLayout> dst, - StringTable* strtab) { + ELFStringTable* strtab) { for (int i = 0, len = src->length(); i < len; i++) { @@ -1023,7 +1023,7 @@ static void CreateSymbolsTable(CodeDescription* desc, int text_section_index) { Zone* zone = desc->info()->zone(); ELFSymbolTable* symtab = new(zone) ELFSymbolTable(".symtab", zone); - StringTable* strtab = new(zone) StringTable(".strtab"); + ELFStringTable* strtab = new(zone) ELFStringTable(".strtab"); // Symbol table should be followed by the linked string table. elf->AddSection(symtab, zone); @@ -1996,7 +1996,7 @@ static GDBJITLineInfo* UntagLineInfo(void* ptr) { } -void GDBJITInterface::AddCode(Handle<String> name, +void GDBJITInterface::AddCode(Handle<Name> name, Handle<Script> script, Handle<Code> code, CompilationInfo* info) { @@ -2005,8 +2005,9 @@ void GDBJITInterface::AddCode(Handle<String> name, // Force initialization of line_ends array. GetScriptLineNumber(script, 0); - if (!name.is_null()) { - SmartArrayPointer<char> name_cstring = name->ToCString(DISALLOW_NULLS); + if (!name.is_null() && name->IsString()) { + SmartArrayPointer<char> name_cstring = + Handle<String>::cast(name)->ToCString(DISALLOW_NULLS); AddCode(*name_cstring, *code, GDBJITInterface::FUNCTION, *script, info); } else { AddCode("", *code, GDBJITInterface::FUNCTION, *script, info); @@ -2124,10 +2125,14 @@ void GDBJITInterface::AddCode(GDBJITInterface::CodeTag tag, void GDBJITInterface::AddCode(GDBJITInterface::CodeTag tag, - String* name, + Name* name, Code* code) { if (!FLAG_gdbjit) return; - AddCode(tag, name != NULL ? *name->ToCString(DISALLOW_NULLS) : NULL, code); + if (name != NULL && name->IsString()) { + AddCode(tag, *String::cast(name)->ToCString(DISALLOW_NULLS), code); + } else { + AddCode(tag, "", code); + } } diff --git a/deps/v8/src/gdb-jit.h b/deps/v8/src/gdb-jit.h index 0eca9384d..cc052c1c0 100644 --- a/deps/v8/src/gdb-jit.h +++ b/deps/v8/src/gdb-jit.h @@ -118,12 +118,12 @@ class GDBJITInterface: public AllStatic { Script* script, CompilationInfo* info); - static void AddCode(Handle<String> name, + static void AddCode(Handle<Name> name, Handle<Script> script, Handle<Code> code, CompilationInfo* info); - static void AddCode(CodeTag tag, String* name, Code* code); + static void AddCode(CodeTag tag, Name* name, Code* code); static void AddCode(CodeTag tag, const char* name, Code* code); diff --git a/deps/v8/src/global-handles.cc b/deps/v8/src/global-handles.cc index 14c00f199..cb3115abf 100644 --- a/deps/v8/src/global-handles.cc +++ b/deps/v8/src/global-handles.cc @@ -72,7 +72,7 @@ class GlobalHandles::Node { Internals::kNodeIsPartiallyDependentShift); } -#ifdef DEBUG +#ifdef ENABLE_EXTRA_CHECKS ~Node() { // TODO(1428): if it's a weak handle we should have invoked its callback. // Zap the values for eager trapping. @@ -111,10 +111,9 @@ class GlobalHandles::Node { void Release(GlobalHandles* global_handles) { ASSERT(state() != FREE); set_state(FREE); - // TODO(mstarzinger): Put behind debug flag once embedders are stabilized. - object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue); -#ifdef DEBUG +#ifdef ENABLE_EXTRA_CHECKS // Zap the values for eager trapping. + object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue); class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; set_independent(false); set_partially_dependent(false); diff --git a/deps/v8/src/handles-inl.h b/deps/v8/src/handles-inl.h index fd60a350d..b763c86a7 100644 --- a/deps/v8/src/handles-inl.h +++ b/deps/v8/src/handles-inl.h @@ -107,7 +107,7 @@ void HandleScope::CloseScope() { current->limit = prev_limit_; DeleteExtensions(isolate_); } -#ifdef DEBUG +#ifdef ENABLE_EXTRA_CHECKS ZapRange(prev_next_, prev_limit_); #endif } diff --git a/deps/v8/src/handles.cc b/deps/v8/src/handles.cc index 2958d2cc0..b24a4cd1d 100644 --- a/deps/v8/src/handles.cc +++ b/deps/v8/src/handles.cc @@ -101,12 +101,14 @@ void HandleScope::DeleteExtensions(Isolate* isolate) { } +#ifdef ENABLE_EXTRA_CHECKS void HandleScope::ZapRange(Object** start, Object** end) { ASSERT(end - start <= kHandleBlockSize); for (Object** p = start; p != end; p++) { *reinterpret_cast<Address*>(p) = v8::internal::kHandleZapValue; } } +#endif Address HandleScope::current_level_address(Isolate* isolate) { @@ -259,20 +261,6 @@ Handle<Object> ForceDeleteProperty(Handle<JSObject> object, } -Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object, - Handle<Name> key, - Handle<Object> value, - PropertyAttributes attributes, - StrictModeFlag strict_mode) { - CALL_HEAP_FUNCTION(object->GetIsolate(), - object->SetPropertyWithInterceptor(*key, - *value, - attributes, - strict_mode), - Object); -} - - Handle<Object> GetProperty(Handle<JSReceiver> obj, const char* name) { Isolate* isolate = obj->GetIsolate(); @@ -289,19 +277,6 @@ Handle<Object> GetProperty(Isolate* isolate, } -Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver, - Handle<JSObject> holder, - Handle<Name> name, - PropertyAttributes* attributes) { - Isolate* isolate = receiver->GetIsolate(); - CALL_HEAP_FUNCTION(isolate, - holder->GetPropertyWithInterceptor(*receiver, - *name, - attributes), - Object); -} - - Handle<Object> SetPrototype(Handle<JSObject> obj, Handle<Object> value) { const bool skip_hidden_prototypes = false; CALL_HEAP_FUNCTION(obj->GetIsolate(), diff --git a/deps/v8/src/handles.h b/deps/v8/src/handles.h index 3e408b73f..c69713e44 100644 --- a/deps/v8/src/handles.h +++ b/deps/v8/src/handles.h @@ -160,13 +160,14 @@ class HandleScope { // Extend the handle scope making room for more handles. static internal::Object** Extend(Isolate* isolate); +#ifdef ENABLE_EXTRA_CHECKS // Zaps the handles in the half-open interval [start, end). static void ZapRange(internal::Object** start, internal::Object** end); +#endif - friend class v8::internal::DeferredHandles; friend class v8::HandleScope; + friend class v8::internal::DeferredHandles; friend class v8::internal::HandleScopeImplementer; - friend class v8::ImplementationUtilities; friend class v8::internal::Isolate; }; @@ -232,11 +233,6 @@ Handle<Object> GetProperty(Isolate* isolate, Handle<Object> obj, Handle<Object> key); -Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver, - Handle<JSObject> holder, - Handle<String> name, - PropertyAttributes* attributes); - Handle<Object> SetPrototype(Handle<JSObject> obj, Handle<Object> value); Handle<Object> LookupSingleCharacterStringFromCode(Isolate* isolate, diff --git a/deps/v8/src/heap-inl.h b/deps/v8/src/heap-inl.h index 9ed65d810..a15b8ef48 100644 --- a/deps/v8/src/heap-inl.h +++ b/deps/v8/src/heap-inl.h @@ -399,7 +399,9 @@ AllocationSpace Heap::TargetSpaceId(InstanceType type) { ASSERT(type != ODDBALL_TYPE); ASSERT(type != JS_GLOBAL_PROPERTY_CELL_TYPE); - if (type < FIRST_NONSTRING_TYPE) { + if (type <= LAST_NAME_TYPE) { + if (type == SYMBOL_TYPE) return OLD_POINTER_SPACE; + ASSERT(type < FIRST_NONSTRING_TYPE); // There are four string representations: sequential strings, external // strings, cons strings, and sliced strings. // Only the latter two contain non-map-word pointers to heap objects. diff --git a/deps/v8/src/heap-profiler.cc b/deps/v8/src/heap-profiler.cc index c9f1d501d..5c1badf9c 100644 --- a/deps/v8/src/heap-profiler.cc +++ b/deps/v8/src/heap-profiler.cc @@ -44,72 +44,13 @@ HeapProfiler::~HeapProfiler() { } -void HeapProfiler::ResetSnapshots() { +void HeapProfiler::DeleteAllSnapshots() { Heap* the_heap = heap(); delete snapshots_; snapshots_ = new HeapSnapshotsCollection(the_heap); } -void HeapProfiler::SetUp() { - Isolate* isolate = Isolate::Current(); - if (isolate->heap_profiler() == NULL) { - isolate->set_heap_profiler(new HeapProfiler(isolate->heap())); - } -} - - -void HeapProfiler::TearDown() { - Isolate* isolate = Isolate::Current(); - delete isolate->heap_profiler(); - isolate->set_heap_profiler(NULL); -} - - -HeapSnapshot* HeapProfiler::TakeSnapshot( - const char* name, - int type, - v8::ActivityControl* control, - v8::HeapProfiler::ObjectNameResolver* resolver) { - ASSERT(Isolate::Current()->heap_profiler() != NULL); - return Isolate::Current()->heap_profiler()->TakeSnapshotImpl(name, - type, - control, - resolver); -} - - -HeapSnapshot* HeapProfiler::TakeSnapshot( - String* name, - int type, - v8::ActivityControl* control, - v8::HeapProfiler::ObjectNameResolver* resolver) { - ASSERT(Isolate::Current()->heap_profiler() != NULL); - return Isolate::Current()->heap_profiler()->TakeSnapshotImpl(name, - type, - control, - resolver); -} - - -void HeapProfiler::StartHeapObjectsTracking() { - ASSERT(Isolate::Current()->heap_profiler() != NULL); - Isolate::Current()->heap_profiler()->StartHeapObjectsTrackingImpl(); -} - - -void HeapProfiler::StopHeapObjectsTracking() { - ASSERT(Isolate::Current()->heap_profiler() != NULL); - Isolate::Current()->heap_profiler()->StopHeapObjectsTrackingImpl(); -} - - -SnapshotObjectId HeapProfiler::PushHeapObjectsStats(v8::OutputStream* stream) { - ASSERT(Isolate::Current()->heap_profiler() != NULL); - return Isolate::Current()->heap_profiler()->PushHeapObjectsStatsImpl(stream); -} - - void HeapProfiler::DefineWrapperClass( uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback) { ASSERT(class_id != v8::HeapProfiler::kPersistentHandleNoClassId); @@ -129,99 +70,69 @@ v8::RetainedObjectInfo* HeapProfiler::ExecuteWrapperClassCallback( } -HeapSnapshot* HeapProfiler::TakeSnapshotImpl( +HeapSnapshot* HeapProfiler::TakeSnapshot( const char* name, - int type, v8::ActivityControl* control, v8::HeapProfiler::ObjectNameResolver* resolver) { - HeapSnapshot::Type s_type = static_cast<HeapSnapshot::Type>(type); - HeapSnapshot* result = - snapshots_->NewSnapshot(s_type, name, next_snapshot_uid_++); - bool generation_completed = true; - switch (s_type) { - case HeapSnapshot::kFull: { - HeapSnapshotGenerator generator(result, control, resolver, heap()); - generation_completed = generator.GenerateSnapshot(); - break; + HeapSnapshot* result = snapshots_->NewSnapshot(name, next_snapshot_uid_++); + { + HeapSnapshotGenerator generator(result, control, resolver, heap()); + if (!generator.GenerateSnapshot()) { + delete result; + result = NULL; } - default: - UNREACHABLE(); - } - if (!generation_completed) { - delete result; - result = NULL; } snapshots_->SnapshotGenerationFinished(result); return result; } -HeapSnapshot* HeapProfiler::TakeSnapshotImpl( +HeapSnapshot* HeapProfiler::TakeSnapshot( String* name, - int type, v8::ActivityControl* control, v8::HeapProfiler::ObjectNameResolver* resolver) { - return TakeSnapshotImpl(snapshots_->names()->GetName(name), type, control, - resolver); + return TakeSnapshot(snapshots_->names()->GetName(name), control, resolver); } -void HeapProfiler::StartHeapObjectsTrackingImpl() { +void HeapProfiler::StartHeapObjectsTracking() { snapshots_->StartHeapObjectsTracking(); } -SnapshotObjectId HeapProfiler::PushHeapObjectsStatsImpl(OutputStream* stream) { +SnapshotObjectId HeapProfiler::PushHeapObjectsStats(OutputStream* stream) { return snapshots_->PushHeapObjectsStats(stream); } -void HeapProfiler::StopHeapObjectsTrackingImpl() { +void HeapProfiler::StopHeapObjectsTracking() { snapshots_->StopHeapObjectsTracking(); } size_t HeapProfiler::GetMemorySizeUsedByProfiler() { - HeapProfiler* profiler = Isolate::Current()->heap_profiler(); - ASSERT(profiler != NULL); - size_t size = profiler->snapshots_->GetUsedMemorySize(); - return size; + return snapshots_->GetUsedMemorySize(); } int HeapProfiler::GetSnapshotsCount() { - HeapProfiler* profiler = Isolate::Current()->heap_profiler(); - ASSERT(profiler != NULL); - return profiler->snapshots_->snapshots()->length(); + return snapshots_->snapshots()->length(); } HeapSnapshot* HeapProfiler::GetSnapshot(int index) { - HeapProfiler* profiler = Isolate::Current()->heap_profiler(); - ASSERT(profiler != NULL); - return profiler->snapshots_->snapshots()->at(index); + return snapshots_->snapshots()->at(index); } HeapSnapshot* HeapProfiler::FindSnapshot(unsigned uid) { - HeapProfiler* profiler = Isolate::Current()->heap_profiler(); - ASSERT(profiler != NULL); - return profiler->snapshots_->GetSnapshot(uid); + return snapshots_->GetSnapshot(uid); } SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Object> obj) { if (!obj->IsHeapObject()) return v8::HeapProfiler::kUnknownObjectId; - HeapProfiler* profiler = Isolate::Current()->heap_profiler(); - ASSERT(profiler != NULL); - return profiler->snapshots_->FindObjectId(HeapObject::cast(*obj)->address()); -} - - -void HeapProfiler::DeleteAllSnapshots() { - HeapProfiler* profiler = Isolate::Current()->heap_profiler(); - ASSERT(profiler != NULL); - profiler->ResetSnapshots(); + return snapshots_->FindObjectId(HeapObject::cast(*obj)->address()); } diff --git a/deps/v8/src/heap-profiler.h b/deps/v8/src/heap-profiler.h index c8c94f58d..3f3138db5 100644 --- a/deps/v8/src/heap-profiler.h +++ b/deps/v8/src/heap-profiler.h @@ -46,30 +46,28 @@ class HeapSnapshotsCollection; class HeapProfiler { public: - static void SetUp(); - static void TearDown(); + explicit HeapProfiler(Heap* heap); + ~HeapProfiler(); - static size_t GetMemorySizeUsedByProfiler(); + size_t GetMemorySizeUsedByProfiler(); - static HeapSnapshot* TakeSnapshot( + HeapSnapshot* TakeSnapshot( const char* name, - int type, v8::ActivityControl* control, v8::HeapProfiler::ObjectNameResolver* resolver); - static HeapSnapshot* TakeSnapshot( + HeapSnapshot* TakeSnapshot( String* name, - int type, v8::ActivityControl* control, v8::HeapProfiler::ObjectNameResolver* resolver); - static void StartHeapObjectsTracking(); - static void StopHeapObjectsTracking(); - static SnapshotObjectId PushHeapObjectsStats(OutputStream* stream); - static int GetSnapshotsCount(); - static HeapSnapshot* GetSnapshot(int index); - static HeapSnapshot* FindSnapshot(unsigned uid); - static SnapshotObjectId GetSnapshotObjectId(Handle<Object> obj); - static void DeleteAllSnapshots(); + void StartHeapObjectsTracking(); + void StopHeapObjectsTracking(); + SnapshotObjectId PushHeapObjectsStats(OutputStream* stream); + int GetSnapshotsCount(); + HeapSnapshot* GetSnapshot(int index); + HeapSnapshot* FindSnapshot(unsigned uid); + SnapshotObjectId GetSnapshotObjectId(Handle<Object> obj); + void DeleteAllSnapshots(); void ObjectMoveEvent(Address from, Address to); @@ -83,24 +81,6 @@ class HeapProfiler { } private: - explicit HeapProfiler(Heap* heap); - ~HeapProfiler(); - HeapSnapshot* TakeSnapshotImpl( - const char* name, - int type, - v8::ActivityControl* control, - v8::HeapProfiler::ObjectNameResolver* resolver); - HeapSnapshot* TakeSnapshotImpl( - String* name, - int type, - v8::ActivityControl* control, - v8::HeapProfiler::ObjectNameResolver* resolver); - void ResetSnapshots(); - - void StartHeapObjectsTrackingImpl(); - void StopHeapObjectsTrackingImpl(); - SnapshotObjectId PushHeapObjectsStatsImpl(OutputStream* stream); - Heap* heap() const { return snapshots_->heap(); } HeapSnapshotsCollection* snapshots_; diff --git a/deps/v8/src/heap-snapshot-generator-inl.h b/deps/v8/src/heap-snapshot-generator-inl.h index 43002d2d2..1a878c6df 100644 --- a/deps/v8/src/heap-snapshot-generator-inl.h +++ b/deps/v8/src/heap-snapshot-generator-inl.h @@ -85,3 +85,4 @@ int V8HeapExplorer::GetGcSubrootOrder(HeapObject* subroot) { } } // namespace v8::internal #endif // V8_HEAP_SNAPSHOT_GENERATOR_INL_H_ + diff --git a/deps/v8/src/heap-snapshot-generator.cc b/deps/v8/src/heap-snapshot-generator.cc index 824e50793..fb239aa3c 100644 --- a/deps/v8/src/heap-snapshot-generator.cc +++ b/deps/v8/src/heap-snapshot-generator.cc @@ -189,7 +189,7 @@ template <> struct SnapshotSizeConstants<4> { static const int kExpectedHeapGraphEdgeSize = 12; static const int kExpectedHeapEntrySize = 24; static const int kExpectedHeapSnapshotsCollectionSize = 100; - static const int kExpectedHeapSnapshotSize = 136; + static const int kExpectedHeapSnapshotSize = 132; static const size_t kMaxSerializableSnapshotRawSize = 256 * MB; }; @@ -197,7 +197,7 @@ template <> struct SnapshotSizeConstants<8> { static const int kExpectedHeapGraphEdgeSize = 24; static const int kExpectedHeapEntrySize = 32; static const int kExpectedHeapSnapshotsCollectionSize = 152; - static const int kExpectedHeapSnapshotSize = 168; + static const int kExpectedHeapSnapshotSize = 160; static const uint64_t kMaxSerializableSnapshotRawSize = static_cast<uint64_t>(6000) * MB; }; @@ -205,11 +205,9 @@ template <> struct SnapshotSizeConstants<8> { } // namespace HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, - HeapSnapshot::Type type, const char* title, unsigned uid) : collection_(collection), - type_(type), title_(title), uid_(uid), root_index_(HeapEntry::kNoEntry), @@ -599,11 +597,10 @@ HeapSnapshotsCollection::~HeapSnapshotsCollection() { } -HeapSnapshot* HeapSnapshotsCollection::NewSnapshot(HeapSnapshot::Type type, - const char* name, +HeapSnapshot* HeapSnapshotsCollection::NewSnapshot(const char* name, unsigned uid) { is_tracking_objects_ = true; // Start watching for heap objects moves. - return new HeapSnapshot(this, type, name, uid); + return new HeapSnapshot(this, name, uid); } @@ -2410,7 +2407,6 @@ void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) { HeapSnapshot* HeapSnapshotJSONSerializer::CreateFakeSnapshot() { HeapSnapshot* result = new HeapSnapshot(snapshot_->collection(), - HeapSnapshot::kFull, snapshot_->title(), snapshot_->uid()); result->AddRootEntry(); diff --git a/deps/v8/src/heap-snapshot-generator.h b/deps/v8/src/heap-snapshot-generator.h index 7331b5f0b..a4fcef72b 100644 --- a/deps/v8/src/heap-snapshot-generator.h +++ b/deps/v8/src/heap-snapshot-generator.h @@ -157,18 +157,12 @@ class HeapSnapshotsCollection; // HeapSnapshotGenerator fills in a HeapSnapshot. class HeapSnapshot { public: - enum Type { - kFull = v8::HeapSnapshot::kFull - }; - HeapSnapshot(HeapSnapshotsCollection* collection, - Type type, const char* title, unsigned uid); void Delete(); HeapSnapshotsCollection* collection() { return collection_; } - Type type() { return type_; } const char* title() { return title_; } unsigned uid() { return uid_; } size_t RawSnapshotSize() const; @@ -203,7 +197,6 @@ class HeapSnapshot { private: HeapSnapshotsCollection* collection_; - Type type_; const char* title_; unsigned uid_; int root_index_; @@ -305,8 +298,7 @@ class HeapSnapshotsCollection { void StartHeapObjectsTracking() { is_tracking_objects_ = true; } void StopHeapObjectsTracking() { ids_.StopHeapObjectsTracking(); } - HeapSnapshot* NewSnapshot( - HeapSnapshot::Type type, const char* name, unsigned uid); + HeapSnapshot* NewSnapshot(const char* name, unsigned uid); void SnapshotGenerationFinished(HeapSnapshot* snapshot); List<HeapSnapshot*>* snapshots() { return &snapshots_; } HeapSnapshot* GetSnapshot(unsigned uid); @@ -695,3 +687,4 @@ class HeapSnapshotJSONSerializer { } } // namespace v8::internal #endif // V8_HEAP_SNAPSHOT_GENERATOR_H_ + diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index 3cf23d036..fafcb64d3 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -1779,6 +1779,10 @@ class ScavengingVisitor : public StaticVisitorBase { &ObjectEvacuationStrategy<POINTER_OBJECT>:: template VisitSpecialized<SlicedString::kSize>); + table_.Register(kVisitSymbol, + &ObjectEvacuationStrategy<POINTER_OBJECT>:: + template VisitSpecialized<Symbol::kSize>); + table_.Register(kVisitSharedFunctionInfo, &ObjectEvacuationStrategy<POINTER_OBJECT>:: template VisitSpecialized<SharedFunctionInfo::kSize>); @@ -3785,11 +3789,7 @@ MaybeObject* Heap::CreateCode(const CodeDesc& desc, ASSERT(!isolate_->code_range()->exists() || isolate_->code_range()->contains(code->address())); code->set_instruction_size(desc.instr_size); - // TODO(mstarzinger): Remove once we found the bug. - CHECK(reloc_info->IsByteArray()); code->set_relocation_info(reloc_info); - // TODO(mstarzinger): Remove once we found the bug. - CHECK(code->relocation_info()->IsByteArray()); code->set_flags(flags); if (code->is_call_stub() || code->is_keyed_call_stub()) { code->set_check_type(RECEIVER_MAP_CHECK); @@ -3805,8 +3805,6 @@ MaybeObject* Heap::CreateCode(const CodeDesc& desc, } // Allow self references to created code object by patching the handle to // point to the newly allocated Code object. - CHECK(code->IsCode()); - CHECK(code->relocation_info()->IsByteArray()); if (!self_reference.is_null()) { *(self_reference.location()) = code; } @@ -3815,8 +3813,6 @@ MaybeObject* Heap::CreateCode(const CodeDesc& desc, // that are dereferenced during the copy to point directly to the actual heap // objects. These pointers can include references to the code object itself, // through the self_reference parameter. - CHECK(code->IsCode()); - CHECK(code->relocation_info()->IsByteArray()); code->CopyFrom(desc); #ifdef VERIFY_HEAP @@ -3888,13 +3884,15 @@ MaybeObject* Heap::CopyCode(Code* code, Vector<byte> reloc_info) { Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); // Copy header and instructions. - memcpy(new_addr, old_addr, relocation_offset); + CopyBytes(new_addr, old_addr, relocation_offset); Code* new_code = Code::cast(result); new_code->set_relocation_info(ByteArray::cast(reloc_info_array)); // Copy patched rinfo. - memcpy(new_code->relocation_start(), reloc_info.start(), reloc_info.length()); + CopyBytes(new_code->relocation_start(), + reloc_info.start(), + static_cast<size_t>(reloc_info.length())); // Relocate the copy. ASSERT(!isolate_->code_range()->exists() || @@ -5430,13 +5428,13 @@ MaybeObject* Heap::AllocateHashTable(int length, PretenureFlag pretenure) { } -MaybeObject* Heap::AllocateSymbol(PretenureFlag pretenure) { +MaybeObject* Heap::AllocateSymbol() { // Statically ensure that it is safe to allocate symbols in paged spaces. STATIC_ASSERT(Symbol::kSize <= Page::kNonCodeObjectAreaSize); - AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; Object* result; - MaybeObject* maybe = AllocateRaw(Symbol::kSize, space, OLD_DATA_SPACE); + MaybeObject* maybe = + AllocateRaw(Symbol::kSize, OLD_POINTER_SPACE, OLD_POINTER_SPACE); if (!maybe->ToObject(&result)) return maybe; HeapObject::cast(result)->set_map_no_write_barrier(symbol_map()); @@ -5452,6 +5450,7 @@ MaybeObject* Heap::AllocateSymbol(PretenureFlag pretenure) { Symbol::cast(result)->set_hash_field( Name::kIsNotArrayIndexMask | (hash << Name::kHashShift)); + Symbol::cast(result)->set_name(undefined_value()); ASSERT(result->IsSymbol()); return result; @@ -7471,6 +7470,9 @@ void KeyedLookupCache::Update(Map* map, Name* name, int field_offset) { } name = internalized_string; } + // This cache is cleared only between mark compact passes, so we expect the + // cache to only contain old space names. + ASSERT(!HEAP->InNewSpace(name)); int index = (Hash(map, name) & kHashMask); // After a GC there will be free slots, so we use them in order (this may diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h index d26c38476..8992e318e 100644 --- a/deps/v8/src/heap.h +++ b/deps/v8/src/heap.h @@ -213,6 +213,8 @@ namespace internal { V(prototype_string, "prototype") \ V(string_string, "string") \ V(String_string, "String") \ + V(symbol_string, "symbol") \ + V(Symbol_string, "Symbol") \ V(Date_string, "Date") \ V(this_string, "this") \ V(to_string_string, "toString") \ @@ -220,6 +222,7 @@ namespace internal { V(undefined_string, "undefined") \ V(value_of_string, "valueOf") \ V(stack_string, "stack") \ + V(toJSON_string, "toJSON") \ V(InitializeVarGlobal_string, "InitializeVarGlobal") \ V(InitializeConstGlobal_string, "InitializeConstGlobal") \ V(KeyedLoadElementMonomorphic_string, \ @@ -520,6 +523,7 @@ class Heap { int InitialSemiSpaceSize() { return initial_semispace_size_; } intptr_t MaxOldGenerationSize() { return max_old_generation_size_; } intptr_t MaxExecutableSize() { return max_executable_size_; } + int MaxNewSpaceAllocationSize() { return InitialSemiSpaceSize() * 3/4; } // Returns the capacity of the heap in bytes w/o growing. Heap grows when // more spaces are needed until it reaches the limit. @@ -878,12 +882,11 @@ class Heap { void* external_pointer, PretenureFlag pretenure); - // Allocate a symbol. + // Allocate a symbol in old space. // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation // failed. // Please note this does not perform a garbage collection. - MUST_USE_RESULT MaybeObject* AllocateSymbol( - PretenureFlag pretenure = NOT_TENURED); + MUST_USE_RESULT MaybeObject* AllocateSymbol(); // Allocate a tenured JS global property cell. // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation diff --git a/deps/v8/src/hydrogen-instructions.cc b/deps/v8/src/hydrogen-instructions.cc index fc80748a6..edbffc2e2 100644 --- a/deps/v8/src/hydrogen-instructions.cc +++ b/deps/v8/src/hydrogen-instructions.cc @@ -1277,7 +1277,8 @@ Representation HBranch::observed_input_representation(int index) { ToBooleanStub::UNDEFINED | ToBooleanStub::NULL_TYPE | ToBooleanStub::SPEC_OBJECT | - ToBooleanStub::STRING); + ToBooleanStub::STRING | + ToBooleanStub::SYMBOL); if (expected_input_types_.ContainsAnyOf(tagged_types)) { return Representation::Tagged(); } else if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) { @@ -1467,15 +1468,6 @@ void HChange::PrintDataTo(StringStream* stream) { } -void HJSArrayLength::PrintDataTo(StringStream* stream) { - value()->PrintNameTo(stream); - if (HasTypeCheck()) { - stream->Add(" "); - typecheck()->PrintNameTo(stream); - } -} - - HValue* HUnaryMathOperation::Canonicalize() { if (op() == kMathFloor) { // If the input is integer32 then we replace the floor instruction @@ -2415,6 +2407,10 @@ void HParameter::PrintDataTo(StringStream* stream) { void HLoadNamedField::PrintDataTo(StringStream* stream) { object()->PrintNameTo(stream); stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : ""); + if (HasTypeCheck()) { + stream->Add(" "); + typecheck()->PrintNameTo(stream); + } } @@ -2589,6 +2585,10 @@ bool HLoadKeyed::UsesMustHandleHole() const { return false; } + if (IsExternalArrayElementsKind(elements_kind())) { + return false; + } + if (hole_mode() == ALLOW_RETURN_HOLE) return true; if (IsFastDoubleElementsKind(elements_kind())) { @@ -2611,6 +2611,10 @@ bool HLoadKeyed::RequiresHoleCheck() const { return false; } + if (IsExternalArrayElementsKind(elements_kind())) { + return false; + } + return !UsesMustHandleHole(); } @@ -3036,10 +3040,19 @@ bool HStoreKeyed::NeedsCanonicalization() { // If value is an integer or smi or comes from the result of a keyed load or // constant then it is either be a non-hole value or in the case of a constant // the hole is only being stored explicitly: no need for canonicalization. - if (value()->IsLoadKeyed() || value()->IsConstant()) { + // + // The exception to that is keyed loads from external float or double arrays: + // these can load arbitrary representation of NaN. + + if (value()->IsConstant()) { return false; } + if (value()->IsLoadKeyed()) { + return IsExternalFloatOrDoubleElementsKind( + HLoadKeyed::cast(value())->elements_kind()); + } + if (value()->IsChange()) { if (HChange::cast(value())->from().IsInteger32()) { return false; diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h index f741f292e..ad0368718 100644 --- a/deps/v8/src/hydrogen-instructions.h +++ b/deps/v8/src/hydrogen-instructions.h @@ -134,7 +134,6 @@ class LChunkBuilder; V(IsStringAndBranch) \ V(IsSmiAndBranch) \ V(IsUndetectableAndBranch) \ - V(JSArrayLength) \ V(LeaveInlined) \ V(LoadContextSlot) \ V(LoadElements) \ @@ -2392,45 +2391,6 @@ class HCallRuntime: public HCall<1> { }; -class HJSArrayLength: public HTemplateInstruction<2> { - public: - HJSArrayLength(HValue* value, HValue* typecheck, - HType type = HType::Tagged()) { - set_type(type); - // The length of an array is stored as a tagged value in the array - // object. It is guaranteed to be 32 bit integer, but it can be - // represented as either a smi or heap number. - SetOperandAt(0, value); - SetOperandAt(1, typecheck != NULL ? typecheck : value); - set_representation(Representation::Tagged()); - SetFlag(kUseGVN); - SetGVNFlag(kDependsOnArrayLengths); - SetGVNFlag(kDependsOnMaps); - } - - virtual Representation RequiredInputRepresentation(int index) { - return Representation::Tagged(); - } - - virtual void PrintDataTo(StringStream* stream); - - HValue* value() { return OperandAt(0); } - HValue* typecheck() { - ASSERT(HasTypeCheck()); - return OperandAt(1); - } - bool HasTypeCheck() const { return OperandAt(0) != OperandAt(1); } - - DECLARE_CONCRETE_INSTRUCTION(JSArrayLength) - - protected: - virtual bool DataEquals(HValue* other_raw) { return true; } - - private: - virtual bool IsDeletable() const { return true; } -}; - - class HFixedArrayBaseLength: public HUnaryOperation { public: explicit HFixedArrayBaseLength(HValue* value) : HUnaryOperation(value) { @@ -4693,6 +4653,14 @@ class HParameter: public HTemplateInstruction<0> { set_representation(Representation::Tagged()); } + explicit HParameter(unsigned index, + ParameterKind kind, + Representation r) + : index_(index), + kind_(kind) { + set_representation(r); + } + unsigned index() const { return index_; } ParameterKind kind() const { return kind_; } @@ -5184,12 +5152,16 @@ class HStoreContextSlot: public HTemplateInstruction<2> { }; -class HLoadNamedField: public HUnaryOperation { +class HLoadNamedField: public HTemplateInstruction<2> { public: - HLoadNamedField(HValue* object, bool is_in_object, int offset) - : HUnaryOperation(object), - is_in_object_(is_in_object), + HLoadNamedField(HValue* object, bool is_in_object, int offset, + HValue* typecheck = NULL) + : is_in_object_(is_in_object), offset_(offset) { + ASSERT(object != NULL); + SetOperandAt(0, object); + SetOperandAt(1, typecheck != NULL ? typecheck : object); + set_representation(Representation::Tagged()); SetFlag(kUseGVN); SetGVNFlag(kDependsOnMaps); @@ -5200,7 +5172,24 @@ class HLoadNamedField: public HUnaryOperation { } } + static HLoadNamedField* NewArrayLength(Zone* zone, HValue* object, + HValue* typecheck, + HType type = HType::Tagged()) { + HLoadNamedField* result = new(zone) HLoadNamedField( + object, true, JSArray::kLengthOffset, typecheck); + result->set_type(type); + result->SetGVNFlag(kDependsOnArrayLengths); + result->ClearGVNFlag(kDependsOnInobjectFields); + return result; + } + HValue* object() { return OperandAt(0); } + HValue* typecheck() { + ASSERT(HasTypeCheck()); + return OperandAt(1); + } + + bool HasTypeCheck() const { return OperandAt(0) != OperandAt(1); } bool is_in_object() const { return is_in_object_; } int offset() const { return offset_; } diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index 14feb5f13..abff7b778 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -113,6 +113,10 @@ void HBasicBlock::AddInstruction(HInstruction* instr) { ASSERT(!IsStartBlock() || !IsFinished()); ASSERT(!instr->IsLinked()); ASSERT(!IsFinished()); + // Make sure that we never add instructions without knowing + // what the previous ast id is. + ASSERT(instr->IsSimulate() || instr->IsGoto() || + !last_environment()->previous_ast_id().IsNone()); if (first_ == NULL) { HBlockEntry* entry = new(zone()) HBlockEntry(); entry->InitializeAsFirst(this); @@ -211,10 +215,12 @@ void HBasicBlock::AddLeaveInlined(HValue* return_value, } -void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { +void HBasicBlock::SetInitialEnvironment(HEnvironment* env, + BailoutId previous_ast_id) { ASSERT(!HasEnvironment()); ASSERT(first() == NULL); UpdateEnvironment(env); + env->set_previous_ast_id(previous_ast_id); } @@ -225,13 +231,17 @@ void HBasicBlock::SetJoinId(BailoutId ast_id) { HBasicBlock* predecessor = predecessors_[i]; ASSERT(predecessor->end()->IsGoto()); HSimulate* simulate = HSimulate::cast(predecessor->end()->previous()); - // We only need to verify the ID once. ASSERT(i != 0 || (predecessor->last_environment()->closure().is_null() || predecessor->last_environment()->closure()->shared() ->VerifyBailoutId(ast_id))); simulate->set_ast_id(ast_id); } + HEnvironment* last_environment = this->last_environment(); + ASSERT(last_environment || IsFinished()); + if (last_environment != NULL) { + last_environment->set_previous_ast_id(ast_id); + } } @@ -291,7 +301,9 @@ void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) { } } else if (!HasEnvironment() && !IsFinished()) { ASSERT(!IsLoopHeader()); - SetInitialEnvironment(pred->last_environment()->Copy()); + HEnvironment* new_env = pred->last_environment()->Copy(); + SetInitialEnvironment(new_env, + pred->last_environment()->previous_ast_id()); } predecessors_.Add(pred, zone()); @@ -542,18 +554,6 @@ void HGraph::Verify(bool do_full_verify) const { HPhi* phi = block->phis()->at(j); phi->Verify(); } - - // Check that all join blocks have predecessors that end with an - // unconditional goto and agree on their environment node id. - if (block->predecessors()->length() >= 2) { - BailoutId id = - block->predecessors()->first()->last_environment()->ast_id(); - for (int k = 0; k < block->predecessors()->length(); k++) { - HBasicBlock* predecessor = block->predecessors()->at(k); - ASSERT(predecessor->end()->IsGoto()); - ASSERT(predecessor->last_environment()->ast_id() == id); - } - } } // Check special property of first block to have no predecessors. @@ -637,50 +637,64 @@ DEFINE_GET_CONSTANT(Hole, the_hole, HType::Tagged(), false) #undef DEFINE_GET_CONSTANT -HGraphBuilder::CheckBuilder::CheckBuilder(HGraphBuilder* builder, BailoutId id) +HGraphBuilder::CheckBuilder::CheckBuilder(HGraphBuilder* builder) : builder_(builder), finished_(false), - id_(id) { + id_(builder->current_block()->last_environment()->previous_ast_id()) { HEnvironment* env = builder->environment(); - failure_block_ = builder->CreateBasicBlock(env->Copy()); - merge_block_ = builder->CreateBasicBlock(env->Copy()); + failure_block_ = builder->CreateBasicBlock(env->CopyWithoutHistory(), id_); + merge_block_ = builder->CreateBasicBlock(env->CopyWithoutHistory(), id_); } -void HGraphBuilder::CheckBuilder::CheckNotUndefined(HValue* value) { +HValue* HGraphBuilder::CheckBuilder::CheckNotUndefined(HValue* value) { HEnvironment* env = builder_->environment(); HIsNilAndBranch* compare = new(zone()) HIsNilAndBranch(value, kStrictEquality, kUndefinedValue); - HBasicBlock* success_block = builder_->CreateBasicBlock(env->Copy()); - HBasicBlock* failure_block = builder_->CreateBasicBlock(env->Copy()); + HBasicBlock* success_block = + builder_->CreateBasicBlock(env->CopyWithoutHistory(), id_); + HBasicBlock* failure_block = + builder_->CreateBasicBlock(env->CopyWithoutHistory(), id_); compare->SetSuccessorAt(0, failure_block); compare->SetSuccessorAt(1, success_block); failure_block->Goto(failure_block_); builder_->current_block()->Finish(compare); builder_->set_current_block(success_block); + return compare; } -void HGraphBuilder::CheckBuilder::CheckIntegerEq(HValue* left, HValue* right) { +HValue* HGraphBuilder::CheckBuilder::CheckIntegerCompare(HValue* left, + HValue* right, + Token::Value op) { HEnvironment* env = builder_->environment(); HCompareIDAndBranch* compare = - new(zone()) HCompareIDAndBranch(left, right, Token::EQ); + new(zone()) HCompareIDAndBranch(left, right, op); compare->AssumeRepresentation(Representation::Integer32()); - HBasicBlock* success_block = builder_->CreateBasicBlock(env->Copy()); - HBasicBlock* failure_block = builder_->CreateBasicBlock(env->Copy()); + HBasicBlock* success_block = + builder_->CreateBasicBlock(env->CopyWithoutHistory(), id_); + HBasicBlock* failure_block = + builder_->CreateBasicBlock(env->CopyWithoutHistory(), id_); compare->SetSuccessorAt(0, success_block); compare->SetSuccessorAt(1, failure_block); failure_block->Goto(failure_block_); builder_->current_block()->Finish(compare); builder_->set_current_block(success_block); + return compare; +} + + +HValue* HGraphBuilder::CheckBuilder::CheckIntegerEq(HValue* left, + HValue* right) { + return CheckIntegerCompare(left, right, Token::EQ); } void HGraphBuilder::CheckBuilder::End() { ASSERT(!finished_); builder_->current_block()->Goto(merge_block_); - failure_block_->FinishExitWithDeoptimization(HDeoptimize::kUseAll); failure_block_->SetJoinId(id_); + failure_block_->FinishExitWithDeoptimization(HDeoptimize::kUseAll); builder_->set_current_block(merge_block_); merge_block_->SetJoinId(id_); finished_ = true; @@ -692,18 +706,19 @@ HConstant* HGraph::GetInvalidContext() { } -HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, BailoutId id) +HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder) : builder_(builder), finished_(false), - id_(id) { + did_else_(false), + id_(builder->current_block()->last_environment()->previous_ast_id()) { HEnvironment* env = builder->environment(); - first_true_block_ = builder->CreateBasicBlock(env->Copy()); + first_true_block_ = builder->CreateBasicBlock(env->Copy(), id_); last_true_block_ = NULL; - first_false_block_ = builder->CreateBasicBlock(env->Copy()); + first_false_block_ = builder->CreateBasicBlock(env->Copy(), id_); } -HInstruction* HGraphBuilder::IfBuilder::BeginTrue( +HInstruction* HGraphBuilder::IfBuilder::BeginIf( HValue* left, HValue* right, Token::Value token, @@ -721,21 +736,46 @@ HInstruction* HGraphBuilder::IfBuilder::BeginTrue( } -void HGraphBuilder::IfBuilder::BeginFalse() { +HInstruction* HGraphBuilder::IfBuilder::BeginIfObjectsEqual( + HValue* left, + HValue* right) { + HCompareObjectEqAndBranch* compare = + new(zone()) HCompareObjectEqAndBranch(left, right); + compare->SetSuccessorAt(0, first_true_block_); + compare->SetSuccessorAt(1, first_false_block_); + builder_->current_block()->Finish(compare); + builder_->set_current_block(first_true_block_); + return compare; +} + + +HInstruction* HGraphBuilder::IfBuilder::BeginIfMapEquals(HValue* value, + Handle<Map> map) { + HCompareMap* compare = new(zone()) + HCompareMap(value, map, first_true_block_, first_false_block_); + builder_->current_block()->Finish(compare); + builder_->set_current_block(first_true_block_); + return compare; +} + + +void HGraphBuilder::IfBuilder::BeginElse() { last_true_block_ = builder_->current_block(); ASSERT(!last_true_block_->IsFinished()); builder_->set_current_block(first_false_block_); + did_else_ = true; } void HGraphBuilder::IfBuilder::End() { ASSERT(!finished_); + if (!did_else_) BeginElse(); ASSERT(!last_true_block_->IsFinished()); HBasicBlock* last_false_block = builder_->current_block(); ASSERT(!last_false_block->IsFinished()); HEnvironment* merge_env = - last_true_block_->last_environment()->Copy(); - merge_block_ = builder_->CreateBasicBlock(merge_env); + last_true_block_->last_environment()->CopyWithoutHistory(); + merge_block_ = builder_->CreateBasicBlock(merge_env, id_); last_true_block_->Goto(merge_block_); last_false_block->Goto(merge_block_); merge_block_->SetJoinId(id_); @@ -746,14 +786,13 @@ void HGraphBuilder::IfBuilder::End() { HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, HValue* context, - LoopBuilder::Direction direction, - BailoutId id) + LoopBuilder::Direction direction) : builder_(builder), context_(context), direction_(direction), - id_(id), + id_(builder->current_block()->last_environment()->previous_ast_id()), finished_(false) { - header_block_ = builder->CreateLoopHeaderBlock(); + header_block_ = builder->CreateLoopHeaderBlock(id_); body_block_ = NULL; exit_block_ = NULL; } @@ -774,8 +813,8 @@ HValue* HGraphBuilder::LoopBuilder::BeginBody( HEnvironment* body_env = env->Copy(); HEnvironment* exit_env = env->Copy(); - body_block_ = builder_->CreateBasicBlock(body_env); - exit_block_ = builder_->CreateBasicBlock(exit_env); + body_block_ = builder_->CreateBasicBlock(body_env, id_); + exit_block_ = builder_->CreateBasicBlock(exit_env, id_); // Remove the phi from the expression stack body_env->Pop(); @@ -856,6 +895,7 @@ void HGraphBuilder::AddSimulate(BailoutId id, RemovableSimulate removable) { ASSERT(current_block() != NULL); current_block()->AddSimulate(id, removable); + environment()->set_previous_ast_id(id); } @@ -890,17 +930,18 @@ HReturn* HGraphBuilder::AddReturn(HValue* value) { } -HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { +HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env, + BailoutId previous_ast_id) { HBasicBlock* b = graph()->CreateBasicBlock(); - b->SetInitialEnvironment(env); + b->SetInitialEnvironment(env, previous_ast_id); return b; } -HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { +HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock(BailoutId previous_ast_id) { HBasicBlock* header = graph()->CreateBasicBlock(); HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); - header->SetInitialEnvironment(entry_env); + header->SetInitialEnvironment(entry_env, previous_ast_id); header->AttachLoopInformation(); return header; } @@ -965,7 +1006,8 @@ HInstruction* HGraphBuilder::BuildFastElementAccess( HValue* val, HValue* load_dependency, ElementsKind elements_kind, - bool is_store) { + bool is_store, + KeyedAccessStoreMode store_mode) { Zone* zone = this->zone(); if (is_store) { ASSERT(val != NULL); @@ -993,6 +1035,99 @@ HInstruction* HGraphBuilder::BuildFastElementAccess( } +HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object, + HValue* elements, + ElementsKind kind, + HValue* length, + HValue* key, + bool is_js_array) { + BailoutId ast_id = environment()->previous_ast_id(); + Zone* zone = this->zone(); + IfBuilder length_checker(this); + + length_checker.BeginIf(length, key, Token::EQ); + + HValue* current_capacity = + AddInstruction(new(zone) HFixedArrayBaseLength(elements)); + + IfBuilder capacity_checker(this); + + capacity_checker.BeginIf(length, current_capacity, Token::EQ); + + HValue* context = environment()->LookupContext(); + + HValue* new_capacity = + BuildNewElementsCapacity(context, current_capacity); + + HValue* new_elements = BuildGrowElementsCapacity(object, elements, + kind, length, + new_capacity); + + environment()->Push(new_elements); + capacity_checker.BeginElse(); + + environment()->Push(elements); + capacity_checker.End(); + + if (is_js_array) { + HValue* new_length = AddInstruction( + HAdd::New(zone, context, length, graph_->GetConstant1())); + new_length->ChangeRepresentation(Representation::Integer32()); + new_length->ClearFlag(HValue::kCanOverflow); + AddSimulate(ast_id, REMOVABLE_SIMULATE); + + Factory* factory = isolate()->factory(); + HInstruction* length_store = AddInstruction(new(zone) HStoreNamedField( + object, + factory->length_field_string(), + new_length, true, + JSArray::kLengthOffset)); + length_store->SetGVNFlag(kChangesArrayLengths); + AddSimulate(ast_id, REMOVABLE_SIMULATE); + } + + length_checker.BeginElse(); + + AddBoundsCheck(key, length, ALLOW_SMI_KEY); + environment()->Push(elements); + + length_checker.End(); + + return environment()->Pop(); +} + + +HValue* HGraphBuilder::BuildCopyElementsOnWrite(HValue* object, + HValue* elements, + ElementsKind kind, + HValue* length) { + Zone* zone = this->zone(); + Heap* heap = isolate()->heap(); + + IfBuilder cow_checker(this); + + cow_checker.BeginIfMapEquals(elements, + Handle<Map>(heap->fixed_cow_array_map())); + + HValue* capacity = + AddInstruction(new(zone) HFixedArrayBaseLength(elements)); + + HValue* new_elements = BuildGrowElementsCapacity(object, elements, + kind, length, + capacity); + + environment()->Push(new_elements); + + cow_checker.BeginElse(); + + environment()->Push(elements); + + cow_checker.End(); + + return environment()->Pop(); +} + + HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( HValue* object, HValue* key, @@ -1001,7 +1136,9 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( bool is_js_array, ElementsKind elements_kind, bool is_store, + KeyedAccessStoreMode store_mode, Representation checked_index_representation) { + ASSERT(!IsExternalArrayElementsKind(elements_kind) || !is_js_array); Zone* zone = this->zone(); // No GVNFlag is necessary for ElementsKind if there is an explicit dependency // on a HElementsTransition instruction. The flag can also be removed if the @@ -1017,46 +1154,91 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( } bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind); bool fast_elements = IsFastObjectElementsKind(elements_kind); - HInstruction* elements = + HValue* elements = AddInstruction(new(zone) HLoadElements(object, mapcheck)); - if (is_store && (fast_elements || fast_smi_only_elements)) { + if (is_store && (fast_elements || fast_smi_only_elements) && + store_mode != STORE_NO_TRANSITION_HANDLE_COW) { HCheckMaps* check_cow_map = new(zone) HCheckMaps( elements, isolate()->factory()->fixed_array_map(), zone); check_cow_map->ClearGVNFlag(kDependsOnElementsKind); AddInstruction(check_cow_map); } HInstruction* length = NULL; - HInstruction* checked_key = NULL; - if (IsExternalArrayElementsKind(elements_kind)) { + if (is_js_array) { + length = AddInstruction( + HLoadNamedField::NewArrayLength(zone, object, mapcheck, HType::Smi())); + } else { length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); - checked_key = AddBoundsCheck( - key, length, ALLOW_SMI_KEY, checked_index_representation); - HLoadExternalArrayPointer* external_elements = - new(zone) HLoadExternalArrayPointer(elements); - AddInstruction(external_elements); - return BuildExternalArrayElementAccess( - external_elements, checked_key, val, mapcheck, - elements_kind, is_store); + } + HValue* checked_key = NULL; + if (IsExternalArrayElementsKind(elements_kind)) { + if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { + HLoadExternalArrayPointer* external_elements = + new(zone) HLoadExternalArrayPointer(elements); + AddInstruction(external_elements); + IfBuilder length_checker(this); + length_checker.BeginIf(key, length, Token::LT); + CheckBuilder negative_checker(this); + HValue* bounds_check = negative_checker.CheckIntegerCompare( + key, graph()->GetConstant0(), Token::GTE); + negative_checker.End(); + HInstruction* result = BuildExternalArrayElementAccess( + external_elements, key, val, bounds_check, + elements_kind, is_store); + AddInstruction(result); + length_checker.End(); + return result; + } else { + ASSERT(store_mode == STANDARD_STORE); + checked_key = AddBoundsCheck( + key, length, ALLOW_SMI_KEY, checked_index_representation); + HLoadExternalArrayPointer* external_elements = + new(zone) HLoadExternalArrayPointer(elements); + AddInstruction(external_elements); + return AddInstruction(BuildExternalArrayElementAccess( + external_elements, checked_key, val, mapcheck, + elements_kind, is_store)); + } } ASSERT(fast_smi_only_elements || fast_elements || IsFastDoubleElementsKind(elements_kind)); - if (is_js_array) { - length = AddInstruction(new(zone) HJSArrayLength(object, mapcheck, - HType::Smi())); + + if (is_store && IsFastSmiElementsKind(elements_kind) && + !val->type().IsSmi()) { + AddInstruction(new(zone) HCheckSmi(val)); + } + + if (IsGrowStoreMode(store_mode)) { + elements = BuildCheckForCapacityGrow(object, elements, elements_kind, + length, key, is_js_array); + checked_key = key; } else { - length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); + checked_key = AddBoundsCheck( + key, length, ALLOW_SMI_KEY, checked_index_representation); + + if (is_store && (fast_elements || fast_smi_only_elements)) { + if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) { + elements = BuildCopyElementsOnWrite(object, elements, elements_kind, + length); + } else { + HCheckMaps* check_cow_map = new(zone) HCheckMaps( + elements, isolate()->factory()->fixed_array_map(), zone); + check_cow_map->ClearGVNFlag(kDependsOnElementsKind); + AddInstruction(check_cow_map); + } + } } - checked_key = AddBoundsCheck( - key, length, ALLOW_SMI_KEY, checked_index_representation); - return BuildFastElementAccess(elements, checked_key, val, mapcheck, - elements_kind, is_store); + return AddInstruction( + BuildFastElementAccess(elements, checked_key, val, mapcheck, + elements_kind, is_store, store_mode)); } -HValue* HGraphBuilder::BuildAllocateElements(HContext* context, +HValue* HGraphBuilder::BuildAllocateElements(HValue* context, ElementsKind kind, HValue* capacity) { + BailoutId ast_id = current_block()->last_environment()->previous_ast_id(); Zone* zone = this->zone(); int elements_size = IsFastDoubleElementsKind(kind) @@ -1096,14 +1278,14 @@ HValue* HGraphBuilder::BuildAllocateElements(HContext* context, Handle<Map> map = IsFastDoubleElementsKind(kind) ? factory->fixed_double_array_map() : factory->fixed_array_map(); - BuildStoreMap(elements, map, BailoutId::StubEntry()); + BuildStoreMap(elements, map, ast_id); Handle<String> fixed_array_length_field_name = factory->length_field_string(); HInstruction* store_length = new(zone) HStoreNamedField(elements, fixed_array_length_field_name, capacity, true, FixedArray::kLengthOffset); AddInstruction(store_length); - AddSimulate(BailoutId::StubEntry(), FIXED_SIMULATE); + AddSimulate(ast_id, REMOVABLE_SIMULATE); return elements; } @@ -1120,7 +1302,7 @@ HInstruction* HGraphBuilder::BuildStoreMap(HValue* object, true, JSObject::kMapOffset); store_map->SetGVNFlag(kChangesMaps); AddInstruction(store_map); - AddSimulate(id, FIXED_SIMULATE); + AddSimulate(id, REMOVABLE_SIMULATE); return store_map; } @@ -1135,17 +1317,131 @@ HInstruction* HGraphBuilder::BuildStoreMap(HValue* object, } -void HGraphBuilder::BuildCopyElements(HContext* context, +HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* context, + HValue* old_capacity) { + Zone* zone = this->zone(); + HValue* half_old_capacity = + AddInstruction(HShr::New(zone, context, old_capacity, + graph_->GetConstant1())); + half_old_capacity->ChangeRepresentation(Representation::Integer32()); + half_old_capacity->ClearFlag(HValue::kCanOverflow); + + HValue* new_capacity = AddInstruction( + HAdd::New(zone, context, half_old_capacity, old_capacity)); + new_capacity->ChangeRepresentation(Representation::Integer32()); + new_capacity->ClearFlag(HValue::kCanOverflow); + + HValue* min_growth = + AddInstruction(new(zone) HConstant(16, Representation::Integer32())); + + new_capacity = AddInstruction( + HAdd::New(zone, context, new_capacity, min_growth)); + new_capacity->ChangeRepresentation(Representation::Integer32()); + new_capacity->ClearFlag(HValue::kCanOverflow); + + return new_capacity; +} + + +void HGraphBuilder::BuildNewSpaceArrayCheck(HValue* length, ElementsKind kind) { + Zone* zone = this->zone(); + Heap* heap = isolate()->heap(); + int element_size = IsFastDoubleElementsKind(kind) ? kDoubleSize + : kPointerSize; + int max_size = heap->MaxNewSpaceAllocationSize() / element_size; + max_size -= JSArray::kSize / element_size; + HConstant* max_size_constant = + new(zone) HConstant(max_size, Representation::Integer32()); + AddInstruction(max_size_constant); + // Since we're forcing Integer32 representation for this HBoundsCheck, + // there's no need to Smi-check the index. + AddInstruction(new(zone) + HBoundsCheck(length, max_size_constant, + DONT_ALLOW_SMI_KEY, Representation::Integer32())); +} + + +HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object, + HValue* elements, + ElementsKind kind, + HValue* length, + HValue* new_capacity) { + Zone* zone = this->zone(); + HValue* context = environment()->LookupContext(); + + BuildNewSpaceArrayCheck(new_capacity, kind); + + HValue* new_elements = + BuildAllocateElements(context, kind, new_capacity); + + BuildCopyElements(context, elements, kind, + new_elements, kind, + length, new_capacity); + + Factory* factory = isolate()->factory(); + HInstruction* elements_store = AddInstruction(new(zone) HStoreNamedField( + object, + factory->elements_field_string(), + new_elements, true, + JSArray::kElementsOffset)); + elements_store->SetGVNFlag(kChangesElementsPointer); + + return new_elements; +} + + +void HGraphBuilder::BuildFillElementsWithHole(HValue* context, + HValue* elements, + ElementsKind elements_kind, + HValue* from, + HValue* to) { + BailoutId ast_id = current_block()->last_environment()->previous_ast_id(); + // Fast elements kinds need to be initialized in case statements below cause + // a garbage collection. + Factory* factory = isolate()->factory(); + + double nan_double = FixedDoubleArray::hole_nan_as_double(); + Zone* zone = this->zone(); + HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) + ? AddInstruction(new(zone) HConstant(factory->the_hole_value(), + Representation::Tagged())) + : AddInstruction(new(zone) HConstant(nan_double, + Representation::Double())); + + LoopBuilder builder(this, context, LoopBuilder::kPostIncrement); + + HValue* key = builder.BeginBody(from, to, Token::LT); + + AddInstruction(new(zone) HStoreKeyed(elements, key, hole, elements_kind)); + AddSimulate(ast_id, REMOVABLE_SIMULATE); + + builder.EndBody(); +} + + +void HGraphBuilder::BuildCopyElements(HValue* context, HValue* from_elements, ElementsKind from_elements_kind, HValue* to_elements, ElementsKind to_elements_kind, - HValue* length) { - LoopBuilder builder(this, context, LoopBuilder::kPostIncrement, - BailoutId::StubEntry()); + HValue* length, + HValue* capacity) { + BailoutId ast_id = environment()->previous_ast_id(); + bool pre_fill_with_holes = + IsFastDoubleElementsKind(from_elements_kind) && + IsFastObjectElementsKind(to_elements_kind); - HValue* key = builder.BeginBody(graph()->GetConstant0(), - length, Token::LT); + if (pre_fill_with_holes) { + // If the copy might trigger a GC, make sure that the FixedArray is + // pre-initialized with holes to make sure that it's always in a consistent + // state. + BuildFillElementsWithHole(context, to_elements, to_elements_kind, + graph()->GetConstant0(), capacity); + } + + LoopBuilder builder(this, context, LoopBuilder::kPostIncrement); + + HValue* key = builder.BeginBody(graph()->GetConstant0(), length, Token::LT); HValue* element = AddInstruction(new(zone()) HLoadKeyed(from_elements, key, NULL, @@ -1154,9 +1450,15 @@ void HGraphBuilder::BuildCopyElements(HContext* context, AddInstruction(new(zone()) HStoreKeyed(to_elements, key, element, to_elements_kind)); - AddSimulate(BailoutId::StubEntry(), REMOVABLE_SIMULATE); + AddSimulate(ast_id, REMOVABLE_SIMULATE); builder.EndBody(); + + if (!pre_fill_with_holes && length != capacity) { + // Fill unused capacity with the hole. + BuildFillElementsWithHole(context, to_elements, to_elements_kind, + key, capacity); + } } @@ -1253,9 +1555,9 @@ HGraph::HGraph(CompilationInfo* info) start_environment_ = new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); } - start_environment_->set_ast_id(BailoutId::FunctionEntry()); entry_block_ = CreateBasicBlock(); - entry_block_->SetInitialEnvironment(start_environment_); + entry_block_->SetInitialEnvironment(start_environment_, + BailoutId::FunctionEntry()); } @@ -3813,6 +4115,10 @@ void HOptimizedGraphBuilder::VisitExpressions( bool HOptimizedGraphBuilder::BuildGraph() { + if (info()->function()->is_generator()) { + Bailout("function is a generator"); + return false; + } Scope* scope = info()->scope(); if (scope->HasIllegalRedeclaration()) { Bailout("function with illegal redeclaration"); @@ -3840,7 +4146,8 @@ bool HOptimizedGraphBuilder::BuildGraph() { // values (but not instructions), present in the initial environment and // not replayed by the Lithium translation. HEnvironment* initial_env = environment()->CopyWithoutHistory(); - HBasicBlock* body_entry = CreateBasicBlock(initial_env); + HBasicBlock* body_entry = CreateBasicBlock(initial_env, + BailoutId::FunctionEntry()); current_block()->Goto(body_entry); body_entry->SetJoinId(BailoutId::FunctionEntry()); set_current_block(body_entry); @@ -4780,19 +5087,7 @@ void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { typecheck->SetSuccessorAt(1, not_spec_object); current_block()->Finish(typecheck); if_spec_object->AddLeaveInlined(return_value, state); - if (!FLAG_harmony_symbols) { - not_spec_object->AddLeaveInlined(receiver, state); - } else { - HHasInstanceTypeAndBranch* symbolcheck = - new(zone()) HHasInstanceTypeAndBranch(return_value, SYMBOL_TYPE); - HBasicBlock* is_symbol = graph()->CreateBasicBlock(); - HBasicBlock* not_symbol = graph()->CreateBasicBlock(); - symbolcheck->SetSuccessorAt(0, is_symbol); - symbolcheck->SetSuccessorAt(1, not_symbol); - not_spec_object->Finish(symbolcheck); - is_symbol->AddLeaveInlined(return_value, state); - not_symbol->AddLeaveInlined(receiver, state); - } + not_spec_object->AddLeaveInlined(receiver, state); } } else if (state->inlining_kind() == SETTER_CALL_RETURN) { // Return from an inlined setter call. The returned value is never used, the @@ -5098,7 +5393,7 @@ void HOptimizedGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { ASSERT(current_block()->HasPredecessor()); ASSERT(current_block() != NULL); bool osr_entry = PreProcessOsrEntry(stmt); - HBasicBlock* loop_entry = CreateLoopHeaderBlock(); + HBasicBlock* loop_entry = CreateLoopHeaderBlock(stmt->EntryId()); current_block()->Goto(loop_entry); set_current_block(loop_entry); if (osr_entry) graph()->set_osr_loop_entry(loop_entry); @@ -5141,7 +5436,7 @@ void HOptimizedGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { ASSERT(current_block()->HasPredecessor()); ASSERT(current_block() != NULL); bool osr_entry = PreProcessOsrEntry(stmt); - HBasicBlock* loop_entry = CreateLoopHeaderBlock(); + HBasicBlock* loop_entry = CreateLoopHeaderBlock(stmt->EntryId()); current_block()->Goto(loop_entry); set_current_block(loop_entry); if (osr_entry) graph()->set_osr_loop_entry(loop_entry); @@ -5188,7 +5483,7 @@ void HOptimizedGraphBuilder::VisitForStatement(ForStatement* stmt) { } ASSERT(current_block() != NULL); bool osr_entry = PreProcessOsrEntry(stmt); - HBasicBlock* loop_entry = CreateLoopHeaderBlock(); + HBasicBlock* loop_entry = CreateLoopHeaderBlock(stmt->EntryId()); current_block()->Goto(loop_entry); set_current_block(loop_entry); if (osr_entry) graph()->set_osr_loop_entry(loop_entry); @@ -5283,7 +5578,7 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) { HForInCacheArray::cast(index_cache)); bool osr_entry = PreProcessOsrEntry(stmt); - HBasicBlock* loop_entry = CreateLoopHeaderBlock(); + HBasicBlock* loop_entry = CreateLoopHeaderBlock(stmt->EntryId()); current_block()->Goto(loop_entry); set_current_block(loop_entry); if (osr_entry) graph()->set_osr_loop_entry(loop_entry); @@ -5996,6 +6291,12 @@ static int ComputeLoadStoreFieldIndex(Handle<Map> type, } +void HOptimizedGraphBuilder::AddCheckMap(HValue* object, Handle<Map> map) { + AddInstruction(new(zone()) HCheckNonSmi(object)); + AddInstruction(new(zone()) HCheckMaps(object, map, zone())); +} + + void HOptimizedGraphBuilder::AddCheckMapsWithTransitions(HValue* object, Handle<Map> map) { AddInstruction(new(zone()) HCheckNonSmi(object)); @@ -6107,15 +6408,40 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic( } -void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( +bool HOptimizedGraphBuilder::HandlePolymorphicArrayLengthLoad( Property* expr, HValue* object, SmallMapList* types, Handle<String> name) { + if (!name->Equals(isolate()->heap()->length_string())) return false; + + for (int i = 0; i < types->length(); i++) { + if (types->at(i)->instance_type() != JS_ARRAY_TYPE) return false; + } + + AddInstruction(new(zone()) HCheckNonSmi(object)); + HInstruction* typecheck = + AddInstruction(HCheckInstanceType::NewIsJSArray(object, zone())); + HInstruction* instr = + HLoadNamedField::NewArrayLength(zone(), object, typecheck); + instr->set_position(expr->position()); + ast_context()->ReturnInstruction(instr, expr->id()); + return true; +} + + +void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, + HValue* object, + SmallMapList* types, + Handle<String> name) { int count = 0; int previous_field_offset = 0; bool previous_field_is_in_object = false; bool is_monomorphic_field = true; + + if (HandlePolymorphicArrayLengthLoad(expr, object, types, name)) + return; + Handle<Map> map; LookupResult lookup(isolate()); for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { @@ -6682,6 +7008,12 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { } +void HOptimizedGraphBuilder::VisitYield(Yield* expr) { + // Generators are not optimized, so we should never get here. + UNREACHABLE(); +} + + void HOptimizedGraphBuilder::VisitThrow(Throw* expr) { ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); @@ -6751,16 +7083,25 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( Handle<Map> map) { // Handle a load from a known field. ASSERT(!map->is_dictionary_map()); + + // Handle access to various length properties + if (name->Equals(isolate()->heap()->length_string())) { + if (map->instance_type() == JS_ARRAY_TYPE) { + AddCheckMapsWithTransitions(object, map); + return HLoadNamedField::NewArrayLength(zone(), object, object); + } + } + LookupResult lookup(isolate()); map->LookupDescriptor(NULL, *name, &lookup); if (lookup.IsField()) { - AddCheckMapsWithTransitions(object, map); + AddCheckMap(object, map); return BuildLoadNamedField(object, map, &lookup); } // Handle a load of a constant known function. if (lookup.IsConstantFunction()) { - AddCheckMapsWithTransitions(object, map); + AddCheckMap(object, map); Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map)); return new(zone()) HConstant(function, Representation::Tagged()); } @@ -6771,7 +7112,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( Handle<JSObject> prototype(JSObject::cast(map->prototype())); Handle<JSObject> holder(lookup.holder()); Handle<Map> holder_map(holder->map()); - AddCheckMapsWithTransitions(object, map); + AddCheckMap(object, map); HInstruction* holder_value = AddInstruction( new(zone()) HCheckPrototypeMaps(prototype, holder, zone())); return BuildLoadNamedField(holder_value, holder_map, &lookup); @@ -6782,7 +7123,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( Handle<JSObject> prototype(JSObject::cast(map->prototype())); Handle<JSObject> holder(lookup.holder()); Handle<Map> holder_map(holder->map()); - AddCheckMapsWithTransitions(object, map); + AddCheckMap(object, map); AddInstruction(new(zone()) HCheckPrototypeMaps(prototype, holder, zone())); Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*holder_map)); return new(zone()) HConstant(function, Representation::Tagged()); @@ -6806,7 +7147,8 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( HValue* val, HValue* dependency, Handle<Map> map, - bool is_store) { + bool is_store, + KeyedAccessStoreMode store_mode) { HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map, zone(), dependency); AddInstruction(mapcheck); @@ -6816,7 +7158,7 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( return BuildUncheckedMonomorphicElementAccess( object, key, val, mapcheck, map->instance_type() == JS_ARRAY_TYPE, - map->elements_kind(), is_store); + map->elements_kind(), is_store, store_mode); } @@ -6871,7 +7213,7 @@ HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( object, key, val, check_maps, most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE, most_general_consolidated_map->elements_kind(), - false); + false, STANDARD_STORE); return instr; } @@ -6884,6 +7226,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( BailoutId ast_id, int position, bool is_store, + KeyedAccessStoreMode store_mode, bool* has_side_effects) { *has_side_effects = false; AddInstruction(new(zone()) HCheckNonSmi(object)); @@ -6894,7 +7237,6 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( HInstruction* consolidated_load = TryBuildConsolidatedElementLoad(object, key, val, maps); if (consolidated_load != NULL) { - AddInstruction(consolidated_load); *has_side_effects |= consolidated_load->HasObservableSideEffects(); if (position != RelocInfo::kNoPosition) { consolidated_load->set_position(position); @@ -6961,8 +7303,9 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) : BuildLoadKeyedGeneric(object, key)); } else { - instr = AddInstruction(BuildMonomorphicElementAccess( - object, key, val, transition, untransitionable_map, is_store)); + instr = BuildMonomorphicElementAccess( + object, key, val, transition, untransitionable_map, is_store, + store_mode); } *has_side_effects |= instr->HasObservableSideEffects(); if (position != RelocInfo::kNoPosition) instr->set_position(position); @@ -7038,12 +7381,13 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( set_current_block(if_jsarray); HInstruction* length; - length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck, - HType::Smi())); + length = AddInstruction( + HLoadNamedField::NewArrayLength(zone(), object, typecheck, + HType::Smi())); checked_key = AddBoundsCheck(key, length, ALLOW_SMI_KEY); access = AddInstruction(BuildFastElementAccess( elements, checked_key, val, elements_kind_branch, - elements_kind, is_store)); + elements_kind, is_store, STANDARD_STORE)); if (!is_store) { Push(access); } @@ -7059,7 +7403,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( checked_key = AddBoundsCheck(key, length, ALLOW_SMI_KEY); access = AddInstruction(BuildFastElementAccess( elements, checked_key, val, elements_kind_branch, - elements_kind, is_store)); + elements_kind, is_store, STANDARD_STORE)); } else if (elements_kind == DICTIONARY_ELEMENTS) { if (is_store) { access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); @@ -7105,23 +7449,26 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( if (map->has_slow_elements_kind()) { instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) : BuildLoadKeyedGeneric(obj, key); + AddInstruction(instr); } else { AddInstruction(new(zone()) HCheckNonSmi(obj)); - instr = BuildMonomorphicElementAccess(obj, key, val, NULL, map, is_store); + instr = BuildMonomorphicElementAccess( + obj, key, val, NULL, map, is_store, expr->GetStoreMode()); } } else if (expr->GetReceiverTypes() != NULL && !expr->GetReceiverTypes()->is_empty()) { return HandlePolymorphicElementAccess( - obj, key, val, expr, ast_id, position, is_store, has_side_effects); + obj, key, val, expr, ast_id, position, is_store, + expr->GetStoreMode(), has_side_effects); } else { if (is_store) { instr = BuildStoreKeyedGeneric(obj, key, val); } else { instr = BuildLoadKeyedGeneric(obj, key); } + AddInstruction(instr); } if (position != RelocInfo::kNoPosition) instr->set_position(position); - AddInstruction(instr); *has_side_effects = instr->HasObservableSideEffects(); return instr; } @@ -7237,13 +7584,7 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) { CHECK_ALIVE(VisitForValue(expr->obj())); HInstruction* instr = NULL; - if (expr->AsProperty()->IsArrayLength()) { - HValue* array = Pop(); - AddInstruction(new(zone()) HCheckNonSmi(array)); - HInstruction* mapcheck = - AddInstruction(HCheckInstanceType::NewIsJSArray(array, zone())); - instr = new(zone()) HJSArrayLength(array, mapcheck); - } else if (expr->IsStringLength()) { + if (expr->IsStringLength()) { HValue* string = Pop(); AddInstruction(new(zone()) HCheckNonSmi(string)); AddInstruction(HCheckInstanceType::NewIsString(string, zone())); @@ -7772,7 +8113,7 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind, AddSimulate(return_id); current_block()->UpdateEnvironment(inner_env); - + inner_env->set_previous_ast_id(BailoutId::FunctionEntry()); ZoneList<HValue*>* arguments_values = NULL; // If the function uses arguments copy current arguments values @@ -9772,16 +10113,6 @@ void HOptimizedGraphBuilder::GenerateIsSpecObject(CallRuntime* call) { } -void HOptimizedGraphBuilder::GenerateIsSymbol(CallRuntime* call) { - ASSERT(call->arguments()->length() == 1); - CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); - HValue* value = Pop(); - HHasInstanceTypeAndBranch* result = - new(zone()) HHasInstanceTypeAndBranch(value, SYMBOL_TYPE); - return ast_context()->ReturnControl(result, call->id()); -} - - void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) { ASSERT(call->arguments()->length() == 1); CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); @@ -10295,6 +10626,7 @@ HEnvironment::HEnvironment(HEnvironment* outer, pop_count_(0), push_count_(0), ast_id_(BailoutId::None()), + previous_ast_id_(BailoutId::None()), zone_(zone) { Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0); } @@ -10311,6 +10643,7 @@ HEnvironment::HEnvironment(Zone* zone, int parameter_count) pop_count_(0), push_count_(0), ast_id_(BailoutId::None()), + previous_ast_id_(BailoutId::None()), zone_(zone) { Initialize(parameter_count, 0, 0); } @@ -10327,6 +10660,7 @@ HEnvironment::HEnvironment(const HEnvironment* other, Zone* zone) pop_count_(0), push_count_(0), ast_id_(other->ast_id()), + previous_ast_id_(BailoutId::None()), zone_(zone) { Initialize(other); } @@ -10347,6 +10681,7 @@ HEnvironment::HEnvironment(HEnvironment* outer, pop_count_(0), push_count_(0), ast_id_(BailoutId::None()), + previous_ast_id_(BailoutId::None()), zone_(zone) { } diff --git a/deps/v8/src/hydrogen.h b/deps/v8/src/hydrogen.h index 7f5326bcb..ef3679eca 100644 --- a/deps/v8/src/hydrogen.h +++ b/deps/v8/src/hydrogen.h @@ -108,7 +108,7 @@ class HBasicBlock: public ZoneObject { bool Dominates(HBasicBlock* other) const; int LoopNestingDepth() const; - void SetInitialEnvironment(HEnvironment* env); + void SetInitialEnvironment(HEnvironment* env, BailoutId previous_id); void ClearEnvironment() { last_environment_ = NULL; } bool HasEnvironment() const { return last_environment_ != NULL; } void UpdateEnvironment(HEnvironment* env) { last_environment_ = env; } @@ -483,6 +483,8 @@ class HEnvironment: public ZoneObject { BailoutId ast_id() const { return ast_id_; } void set_ast_id(BailoutId id) { ast_id_ = id; } + BailoutId previous_ast_id() const { return previous_ast_id_; } + void set_previous_ast_id(BailoutId id) { previous_ast_id_ = id; } HEnterInlined* entry() const { return entry_; } void set_entry(HEnterInlined* entry) { entry_ = entry; } @@ -644,6 +646,7 @@ class HEnvironment: public ZoneObject { int pop_count_; int push_count_; BailoutId ast_id_; + BailoutId previous_ast_id_; Zone* zone_; }; @@ -891,8 +894,9 @@ class HGraphBuilder { protected: virtual bool BuildGraph() = 0; - HBasicBlock* CreateBasicBlock(HEnvironment* env); - HBasicBlock* CreateLoopHeaderBlock(); + HBasicBlock* CreateBasicBlock(HEnvironment* envy, + BailoutId previous_ast_id); + HBasicBlock* CreateLoopHeaderBlock(BailoutId previous_ast_id); // Building common constructs HInstruction* BuildExternalArrayElementAccess( @@ -909,7 +913,20 @@ class HGraphBuilder { HValue* val, HValue* dependency, ElementsKind elements_kind, - bool is_store); + bool is_store, + KeyedAccessStoreMode store_mode); + + HValue* BuildCheckForCapacityGrow(HValue* object, + HValue* elements, + ElementsKind kind, + HValue* length, + HValue* key, + bool is_js_array); + + HValue* BuildCopyElementsOnWrite(HValue* object, + HValue* elements, + ElementsKind kind, + HValue* length); HInstruction* BuildUncheckedMonomorphicElementAccess( HValue* object, @@ -919,6 +936,7 @@ class HGraphBuilder { bool is_js_array, ElementsKind elements_kind, bool is_store, + KeyedAccessStoreMode store_mode, Representation checked_index_representation = Representation::None()); HInstruction* BuildStoreMap(HValue* object, HValue* map, BailoutId id); @@ -926,13 +944,14 @@ class HGraphBuilder { class CheckBuilder { public: - CheckBuilder(HGraphBuilder* builder, BailoutId id); + explicit CheckBuilder(HGraphBuilder* builder); ~CheckBuilder() { if (!finished_) End(); } - void CheckNotUndefined(HValue* value); - void CheckIntegerEq(HValue* left, HValue* right); + HValue* CheckNotUndefined(HValue* value); + HValue* CheckIntegerCompare(HValue* left, HValue* right, Token::Value op); + HValue* CheckIntegerEq(HValue* left, HValue* right); void End(); private: @@ -947,17 +966,19 @@ class HGraphBuilder { class IfBuilder { public: - IfBuilder(HGraphBuilder* builder, BailoutId id); + explicit IfBuilder(HGraphBuilder* builder); ~IfBuilder() { if (!finished_) End(); } - HInstruction* BeginTrue( + HInstruction* BeginIf( HValue* left, HValue* right, Token::Value token, Representation input_representation = Representation::Integer32()); - void BeginFalse(); + HInstruction* BeginIfObjectsEqual(HValue* left, HValue* right); + HInstruction* BeginIfMapEquals(HValue* value, Handle<Map> map); + void BeginElse(); void End(); private: @@ -965,6 +986,7 @@ class HGraphBuilder { HGraphBuilder* builder_; bool finished_; + bool did_else_; HBasicBlock* first_true_block_; HBasicBlock* last_true_block_; HBasicBlock* first_false_block_; @@ -983,8 +1005,7 @@ class HGraphBuilder { LoopBuilder(HGraphBuilder* builder, HValue* context, - Direction direction, - BailoutId id); + Direction direction); ~LoopBuilder() { ASSERT(finished_); } @@ -1011,16 +1032,35 @@ class HGraphBuilder { bool finished_; }; - HValue* BuildAllocateElements(HContext* context, + HValue* BuildNewElementsCapacity(HValue* context, + HValue* old_capacity); + + void BuildNewSpaceArrayCheck(HValue* length, + ElementsKind kind); + + HValue* BuildAllocateElements(HValue* context, ElementsKind kind, HValue* capacity); - void BuildCopyElements(HContext* context, + HValue* BuildGrowElementsCapacity(HValue* object, + HValue* elements, + ElementsKind kind, + HValue* length, + HValue* new_capacity); + + void BuildFillElementsWithHole(HValue* context, + HValue* elements, + ElementsKind elements_kind, + HValue* from, + HValue* to); + + void BuildCopyElements(HValue* context, HValue* from_elements, ElementsKind from_elements_kind, HValue* to_elements, ElementsKind to_elements_kind, - HValue* length); + HValue* length, + HValue* capacity); private: HGraphBuilder(); @@ -1311,6 +1351,10 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor { HValue* object, SmallMapList* types, Handle<String> name); + bool HandlePolymorphicArrayLengthLoad(Property* expr, + HValue* object, + SmallMapList* types, + Handle<String> name); void HandlePolymorphicStoreNamedField(Assignment* expr, HValue* object, HValue* value, @@ -1348,7 +1392,8 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor { HValue* val, HValue* dependency, Handle<Map> map, - bool is_store); + bool is_store, + KeyedAccessStoreMode store_mode); HValue* HandlePolymorphicElementAccess(HValue* object, HValue* key, @@ -1357,6 +1402,7 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor { BailoutId ast_id, int position, bool is_store, + KeyedAccessStoreMode store_mode, bool* has_side_effects); HValue* HandleKeyedElementAccess(HValue* obj, @@ -1383,6 +1429,8 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor { Property* expr, Handle<Map> map); + void AddCheckMap(HValue* object, Handle<Map> map); + void AddCheckMapsWithTransitions(HValue* object, Handle<Map> map); diff --git a/deps/v8/src/ia32/builtins-ia32.cc b/deps/v8/src/ia32/builtins-ia32.cc index afb1c030e..e861db3ac 100644 --- a/deps/v8/src/ia32/builtins-ia32.cc +++ b/deps/v8/src/ia32/builtins-ia32.cc @@ -216,8 +216,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // eax: initial map __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset)); __ shl(edi, kPointerSizeLog2); - __ AllocateInNewSpace( - edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS); + __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS); // Allocated the JSObject, now initialize the fields. // eax: initial map // ebx: JSObject @@ -280,15 +279,15 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // ebx: JSObject // edi: start of next object (will be start of FixedArray) // edx: number of elements in properties array - __ AllocateInNewSpace(FixedArray::kHeaderSize, - times_pointer_size, - edx, - REGISTER_VALUE_IS_INT32, - edi, - ecx, - no_reg, - &undo_allocation, - RESULT_CONTAINS_TOP); + __ Allocate(FixedArray::kHeaderSize, + times_pointer_size, + edx, + REGISTER_VALUE_IS_INT32, + edi, + ecx, + no_reg, + &undo_allocation, + RESULT_CONTAINS_TOP); // Initialize the FixedArray. // ebx: JSObject @@ -409,10 +408,6 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); __ j(above_equal, &exit); - // Symbols are "objects". - __ CmpInstanceType(ecx, SYMBOL_TYPE); - __ j(equal, &exit); - // Throw away the result of the constructor invocation and use the // on-stack receiver as the result. __ bind(&use_receiver); @@ -1129,15 +1124,15 @@ static void AllocateJSArray(MacroAssembler* masm, // Allocate the JSArray object together with space for a FixedArray with the // requested elements. STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); - __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize, - times_pointer_size, - array_size, - REGISTER_VALUE_IS_SMI, - result, - elements_array_end, - scratch, - gc_required, - TAG_OBJECT); + __ Allocate(JSArray::kSize + FixedArray::kHeaderSize, + times_pointer_size, + array_size, + REGISTER_VALUE_IS_SMI, + result, + elements_array_end, + scratch, + gc_required, + TAG_OBJECT); // Allocated the JSArray. Now initialize the fields except for the elements // array. diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc index 88207c490..9b77c50c0 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.cc +++ b/deps/v8/src/ia32/code-stubs-ia32.cc @@ -67,6 +67,17 @@ void KeyedLoadFastElementStub::InitializeInterfaceDescriptor( } +void KeyedStoreFastElementStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + static Register registers[] = { edx, ecx, eax }; + descriptor->register_param_count_ = 3; + descriptor->register_params_ = registers; + descriptor->deoptimization_handler_ = + FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure); +} + + void TransitionElementsKindStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { @@ -89,7 +100,7 @@ static void InitializeArrayConstructorDescriptor(Isolate* isolate, // stack param count needs (constructor pointer, and single argument) descriptor->stack_parameter_count_ = &eax; descriptor->register_params_ = registers; - descriptor->extra_expression_stack_count_ = 1; + descriptor->function_mode_ = JS_FUNCTION_STUB_MODE; descriptor->deoptimization_handler_ = FUNCTION_ADDR(ArrayConstructor_StubFailure); } @@ -621,6 +632,14 @@ void ToBooleanStub::Generate(MacroAssembler* masm) { __ bind(¬_string); } + if (types_.Contains(SYMBOL)) { + // Symbol value -> true. + Label not_symbol; + __ CmpInstanceType(map, SYMBOL_TYPE); + __ j(not_equal, ¬_symbol, Label::kNear); + __ bind(¬_symbol); + } + if (types_.Contains(HEAP_NUMBER)) { // heap number -> false iff +0, -0, or NaN. Label not_heap_number, false_result; @@ -3285,25 +3304,6 @@ void MathPowStub::Generate(MacroAssembler* masm) { } -void ArrayLengthStub::Generate(MacroAssembler* masm) { - // ----------- S t a t e ------------- - // -- ecx : name - // -- edx : receiver - // -- esp[0] : return address - // ----------------------------------- - Label miss; - - if (kind() == Code::KEYED_LOAD_IC) { - __ cmp(ecx, Immediate(masm->isolate()->factory()->length_string())); - __ j(not_equal, &miss); - } - - StubCompiler::GenerateLoadArrayLength(masm, edx, eax, &miss); - __ bind(&miss); - StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind())); -} - - void FunctionPrototypeStub::Generate(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- ecx : name @@ -3558,7 +3558,7 @@ void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { __ add(ebx, Immediate(Heap::kArgumentsObjectSize)); // Do the allocation of all three objects in one go. - __ AllocateInNewSpace(ebx, eax, edx, edi, &runtime, TAG_OBJECT); + __ Allocate(ebx, eax, edx, edi, &runtime, TAG_OBJECT); // eax = address of new object(s) (tagged) // ecx = argument count (tagged) @@ -3756,7 +3756,7 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { __ add(ecx, Immediate(Heap::kArgumentsObjectSizeStrict)); // Do the allocation of both objects in one go. - __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT); + __ Allocate(ecx, eax, edx, ebx, &runtime, TAG_OBJECT); // Get the arguments boilerplate from the current native context. __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); @@ -4280,15 +4280,15 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) { // Allocate RegExpResult followed by FixedArray with size in ebx. // JSArray: [Map][empty properties][Elements][Length-smi][index][input] // Elements: [Map][Length][..elements..] - __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize, - times_pointer_size, - ebx, // In: Number of elements as a smi - REGISTER_VALUE_IS_SMI, - eax, // Out: Start of allocation (tagged). - ecx, // Out: End of allocation. - edx, // Scratch register - &slowcase, - TAG_OBJECT); + __ Allocate(JSRegExpResult::kSize + FixedArray::kHeaderSize, + times_pointer_size, + ebx, // In: Number of elements as a smi + REGISTER_VALUE_IS_SMI, + eax, // Out: Start of allocation (tagged). + ecx, // Out: End of allocation. + edx, // Scratch register + &slowcase, + TAG_OBJECT); // eax: Start of allocated area, object-tagged. // Set JSArray map to global.regexp_result_map(). @@ -4525,6 +4525,7 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { // Identical objects can be compared fast, but there are some tricky cases // for NaN and undefined. + Label generic_heap_number_comparison; { Label not_identical; __ cmp(eax, edx); @@ -4541,12 +4542,11 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { __ bind(&check_for_nan); } - // Test for NaN. Sadly, we can't just compare to factory->nan_value(), - // so we do the second best thing - test it ourselves. - Label heap_number; + // Test for NaN. Compare heap numbers in a general way, + // to hanlde NaNs correctly. __ cmp(FieldOperand(edx, HeapObject::kMapOffset), Immediate(masm->isolate()->factory()->heap_number_map())); - __ j(equal, &heap_number, Label::kNear); + __ j(equal, &generic_heap_number_comparison, Label::kNear); if (cc != equal) { // Call runtime on identical JSObjects. Otherwise return equal. __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); @@ -4555,37 +4555,6 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { __ Set(eax, Immediate(Smi::FromInt(EQUAL))); __ ret(0); - __ bind(&heap_number); - // It is a heap number, so return non-equal if it's NaN and equal if - // it's not NaN. - // The representation of NaN values has all exponent bits (52..62) set, - // and not all mantissa bits (0..51) clear. - // We only accept QNaNs, which have bit 51 set. - // Read top bits of double representation (second word of value). - - // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., - // all bits in the mask are set. We only need to check the word - // that contains the exponent and high bit of the mantissa. - STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0); - __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset)); - __ Set(eax, Immediate(0)); - // Shift value and mask so kQuietNaNHighBitsMask applies to topmost - // bits. - __ add(edx, edx); - __ cmp(edx, kQuietNaNHighBitsMask << 1); - if (cc == equal) { - STATIC_ASSERT(EQUAL != 1); - __ setcc(above_equal, eax); - __ ret(0); - } else { - Label nan; - __ j(above_equal, &nan, Label::kNear); - __ Set(eax, Immediate(Smi::FromInt(EQUAL))); - __ ret(0); - __ bind(&nan); - __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc)))); - __ ret(0); - } __ bind(¬_identical); } @@ -4665,6 +4634,7 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { // Generate the number comparison code. Label non_number_comparison; Label unordered; + __ bind(&generic_heap_number_comparison); if (CpuFeatures::IsSupported(SSE2)) { CpuFeatureScope use_sse2(masm, SSE2); CpuFeatureScope use_cmov(masm, CMOV); @@ -7825,8 +7795,10 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) { __ mov(ebx, MemOperand(ebp, parameter_count_offset)); masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE); __ pop(ecx); - __ lea(esp, MemOperand(esp, ebx, times_pointer_size, - extra_expression_stack_count_ * kPointerSize)); + int additional_offset = function_mode_ == JS_FUNCTION_STUB_MODE + ? kPointerSize + : 0; + __ lea(esp, MemOperand(esp, ebx, times_pointer_size, additional_offset)); __ jmp(ecx); // Return to IC Miss stub, continuation still on stack. } diff --git a/deps/v8/src/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc index b3fce81a3..550c83d51 100644 --- a/deps/v8/src/ia32/codegen-ia32.cc +++ b/deps/v8/src/ia32/codegen-ia32.cc @@ -450,9 +450,8 @@ void ElementsTransitionGenerator::GenerateSmiToDouble( // edi: length of source FixedArray (smi-tagged) AllocationFlags flags = static_cast<AllocationFlags>(TAG_OBJECT | DOUBLE_ALIGNMENT); - __ AllocateInNewSpace(FixedDoubleArray::kHeaderSize, times_8, - edi, REGISTER_VALUE_IS_SMI, - eax, ebx, no_reg, &gc_required, flags); + __ Allocate(FixedDoubleArray::kHeaderSize, times_8, edi, + REGISTER_VALUE_IS_SMI, eax, ebx, no_reg, &gc_required, flags); // eax: destination FixedDoubleArray // edi: number of elements @@ -589,7 +588,7 @@ void ElementsTransitionGenerator::GenerateDoubleToObject( // Allocate new FixedArray. // ebx: length of source FixedDoubleArray (smi-tagged) __ lea(edi, Operand(ebx, times_2, FixedArray::kHeaderSize)); - __ AllocateInNewSpace(edi, eax, esi, no_reg, &gc_required, TAG_OBJECT); + __ Allocate(edi, eax, esi, no_reg, &gc_required, TAG_OBJECT); // eax: destination FixedArray // ebx: number of elements @@ -952,7 +951,7 @@ void Code::PatchPlatformCodeAge(byte* sequence, uint32_t young_length; byte* young_sequence = GetNoCodeAgeSequence(&young_length); if (age == kNoAge) { - memcpy(sequence, young_sequence, young_length); + CopyBytes(sequence, young_sequence, young_length); CPU::FlushICache(sequence, young_length); } else { Code* stub = GetCodeAgeStub(age, parity); diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc index ebc3a2bd5..efbdf1354 100644 --- a/deps/v8/src/ia32/full-codegen-ia32.cc +++ b/deps/v8/src/ia32/full-codegen-ia32.cc @@ -2567,7 +2567,6 @@ void FullCodeGenerator::EmitIsObject(CallRuntime* expr) { void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) { - // TODO(rossberg): incorporate symbols. ZoneList<Expression*>* args = expr->arguments(); ASSERT(args->length() == 1); @@ -2703,28 +2702,6 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( } -void FullCodeGenerator::EmitIsSymbol(CallRuntime* expr) { - ZoneList<Expression*>* args = expr->arguments(); - ASSERT(args->length() == 1); - - VisitForAccumulatorValue(args->at(0)); - - Label materialize_true, materialize_false; - Label* if_true = NULL; - Label* if_false = NULL; - Label* fall_through = NULL; - context()->PrepareTest(&materialize_true, &materialize_false, - &if_true, &if_false, &fall_through); - - __ JumpIfSmi(eax, if_false); - __ CmpObjectType(eax, SYMBOL_TYPE, ebx); - PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - Split(equal, if_true, if_false, fall_through); - - context()->Plug(if_true, if_false); -} - - void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) { ZoneList<Expression*>* args = expr->arguments(); ASSERT(args->length() == 1); @@ -4275,6 +4252,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ test_b(FieldOperand(edx, Map::kBitFieldOffset), 1 << Map::kIsUndetectable); Split(zero, if_true, if_false, fall_through); + } else if (check->Equals(isolate()->heap()->symbol_string())) { + __ JumpIfSmi(eax, if_false); + __ CmpObjectType(eax, SYMBOL_TYPE, edx); + Split(equal, if_true, if_false, fall_through); } else if (check->Equals(isolate()->heap()->boolean_string())) { __ cmp(eax, isolate()->factory()->true_value()); __ j(equal, if_true); @@ -4306,10 +4287,6 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ cmp(eax, isolate()->factory()->null_value()); __ j(equal, if_true); } - if (FLAG_harmony_symbols) { - __ CmpObjectType(eax, SYMBOL_TYPE, edx); - __ j(equal, if_true); - } __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx); __ j(below, if_false); __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc index 205781b9d..4d23aef15 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.cc +++ b/deps/v8/src/ia32/lithium-codegen-ia32.cc @@ -1740,13 +1740,6 @@ void LCodeGen::DoConstantT(LConstantT* instr) { } -void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { - Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->value()); - __ mov(result, FieldOperand(array, JSArray::kLengthOffset)); -} - - void LCodeGen::DoFixedArrayBaseLength( LFixedArrayBaseLength* instr) { Register result = ToRegister(instr->result()); @@ -2116,6 +2109,12 @@ void LCodeGen::DoBranch(LBranch* instr) { __ bind(¬_string); } + if (expected.Contains(ToBooleanStub::SYMBOL)) { + // Symbol value -> true. + __ CmpInstanceType(map, SYMBOL_TYPE); + __ j(equal, true_label); + } + if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { // heap number -> false iff +0, -0, or NaN. Label not_heap_number; @@ -5566,7 +5565,7 @@ void LCodeGen::DoAllocate(LAllocate* instr) { __ Allocate(size, result, temp, no_reg, deferred->entry(), flags); } else { Register size = ToRegister(instr->size()); - __ AllocateInNewSpace(size, result, temp, no_reg, deferred->entry(), flags); + __ Allocate(size, result, temp, no_reg, deferred->entry(), flags); } __ bind(deferred->exit()); @@ -5979,6 +5978,11 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, 1 << Map::kIsUndetectable); final_branch_condition = zero; + } else if (type_name->Equals(heap()->symbol_string())) { + __ JumpIfSmi(input, false_label); + __ CmpObjectType(input, SYMBOL_TYPE, input); + final_branch_condition = equal; + } else if (type_name->Equals(heap()->boolean_string())) { __ cmp(input, factory()->true_value()); __ j(equal, true_label); @@ -6013,13 +6017,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, __ cmp(input, factory()->null_value()); __ j(equal, true_label); } - if (FLAG_harmony_symbols) { - __ CmpObjectType(input, SYMBOL_TYPE, input); - __ j(equal, true_label); - __ CmpInstanceType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); - } else { - __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); - } + __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); __ j(below, false_label); __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); __ j(above, false_label); diff --git a/deps/v8/src/ia32/lithium-ia32.cc b/deps/v8/src/ia32/lithium-ia32.cc index f2aec9977..102515a91 100644 --- a/deps/v8/src/ia32/lithium-ia32.cc +++ b/deps/v8/src/ia32/lithium-ia32.cc @@ -923,6 +923,35 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { LInstruction* instr = current->CompileToLithium(this); if (instr != NULL) { +#if DEBUG + // Make sure that the lithium instruction has either no fixed register + // constraints in temps or the result OR no uses that are only used at + // start. If this invariant doesn't hold, the register allocator can decide + // to insert a split of a range immediately before the instruction due to an + // already allocated register needing to be used for the instruction's fixed + // register constraint. In this case, The register allocator won't see an + // interference between the split child and the use-at-start (it would if + // the it was just a plain use), so it is free to move the split child into + // the same register that is used for the use-at-start. + // See https://code.google.com/p/chromium/issues/detail?id=201590 + if (!(instr->ClobbersRegisters() && instr->ClobbersDoubleRegisters())) { + int fixed = 0; + int used_at_start = 0; + for (UseIterator it(instr); !it.Done(); it.Advance()) { + LUnallocated* operand = LUnallocated::cast(it.Current()); + if (operand->IsUsedAtStart()) ++used_at_start; + } + if (instr->Output() != NULL) { + if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed; + } + for (TempIterator it(instr); !it.Done(); it.Advance()) { + LUnallocated* operand = LUnallocated::cast(it.Current()); + if (operand->HasFixedPolicy()) ++fixed; + } + ASSERT(fixed == 0 || used_at_start == 0); + } +#endif + if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) { instr = AssignPointerMap(instr); } @@ -1182,16 +1211,20 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { input); return MarkAsCall(DefineFixedDouble(result, xmm1), instr); } else { - LOperand* input = UseRegisterAtStart(instr->value()); LOperand* context = UseAny(instr->context()); // Deferred use by MathAbs. + LOperand* input = NULL; if (op == kMathPowHalf) { + input = UseRegisterAtStart(instr->value()); LOperand* temp = TempRegister(); LMathPowHalf* result = new(zone()) LMathPowHalf(context, input, temp); return DefineSameAsFirst(result); } else if (op == kMathRound) { + input = UseRegister(instr->value()); LOperand* temp = FixedTemp(xmm4); LMathRound* result = new(zone()) LMathRound(context, input, temp); return AssignEnvironment(DefineAsRegister(result)); + } else { + input = UseRegisterAtStart(instr->value()); } LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context, input); @@ -1716,12 +1749,6 @@ LInstruction* LChunkBuilder::DoClassOfTestAndBranch( } -LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) { - LOperand* array = UseRegisterAtStart(instr->value()); - return DefineAsRegister(new(zone()) LJSArrayLength(array)); -} - - LInstruction* LChunkBuilder::DoFixedArrayBaseLength( HFixedArrayBaseLength* instr) { LOperand* array = UseRegisterAtStart(instr->value()); diff --git a/deps/v8/src/ia32/lithium-ia32.h b/deps/v8/src/ia32/lithium-ia32.h index 0e3647407..1c490bb57 100644 --- a/deps/v8/src/ia32/lithium-ia32.h +++ b/deps/v8/src/ia32/lithium-ia32.h @@ -114,7 +114,6 @@ class LCodeGen; V(IsStringAndBranch) \ V(IsSmiAndBranch) \ V(IsUndetectableAndBranch) \ - V(JSArrayLength) \ V(Label) \ V(LazyBailout) \ V(LoadContextSlot) \ @@ -1147,19 +1146,6 @@ class LCmpMapAndBranch: public LTemplateInstruction<0, 1, 0> { }; -class LJSArrayLength: public LTemplateInstruction<1, 1, 0> { - public: - explicit LJSArrayLength(LOperand* value) { - inputs_[0] = value; - } - - LOperand* value() { return inputs_[0]; } - - DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length") - DECLARE_HYDROGEN_ACCESSOR(JSArrayLength) -}; - - class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> { public: explicit LFixedArrayBaseLength(LOperand* value) { diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc index debf64aa1..3d3dabca4 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/macro-assembler-ia32.cc @@ -1332,18 +1332,16 @@ void MacroAssembler::Allocate(int object_size, } -void MacroAssembler::AllocateInNewSpace( - int header_size, - ScaleFactor element_size, - Register element_count, - RegisterValueType element_count_type, - Register result, - Register result_end, - Register scratch, - Label* gc_required, - AllocationFlags flags) { +void MacroAssembler::Allocate(int header_size, + ScaleFactor element_size, + Register element_count, + RegisterValueType element_count_type, + Register result, + Register result_end, + Register scratch, + Label* gc_required, + AllocationFlags flags) { ASSERT((flags & SIZE_IN_WORDS) == 0); - ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0); if (!FLAG_inline_new) { if (emit_debug_code()) { // Trash the registers to simulate an allocation failure. @@ -1365,6 +1363,7 @@ void MacroAssembler::AllocateInNewSpace( // Align the next allocation. Storing the filler map without checking top is // always safe because the limit of the heap is always aligned. if ((flags & DOUBLE_ALIGNMENT) != 0) { + ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0); ASSERT(kPointerAlignment * 2 == kDoubleAlignment); Label aligned; test(result, Immediate(kDoubleAlignmentMask)); @@ -1375,9 +1374,9 @@ void MacroAssembler::AllocateInNewSpace( bind(&aligned); } - // Calculate new top and bail out if new space is exhausted. - ExternalReference new_space_allocation_limit = - ExternalReference::new_space_allocation_limit_address(isolate()); + // Calculate new top and bail out if space is exhausted. + ExternalReference allocation_limit = + AllocationUtils::GetAllocationLimitReference(isolate(), flags); // We assume that element_count*element_size + header_size does not // overflow. @@ -1394,7 +1393,7 @@ void MacroAssembler::AllocateInNewSpace( lea(result_end, Operand(element_count, element_size, header_size)); add(result_end, result); j(carry, gc_required); - cmp(result_end, Operand::StaticVariable(new_space_allocation_limit)); + cmp(result_end, Operand::StaticVariable(allocation_limit)); j(above, gc_required); if ((flags & TAG_OBJECT) != 0) { @@ -1407,14 +1406,13 @@ void MacroAssembler::AllocateInNewSpace( } -void MacroAssembler::AllocateInNewSpace(Register object_size, - Register result, - Register result_end, - Register scratch, - Label* gc_required, - AllocationFlags flags) { +void MacroAssembler::Allocate(Register object_size, + Register result, + Register result_end, + Register scratch, + Label* gc_required, + AllocationFlags flags) { ASSERT((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0); - ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0); if (!FLAG_inline_new) { if (emit_debug_code()) { // Trash the registers to simulate an allocation failure. @@ -1436,6 +1434,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size, // Align the next allocation. Storing the filler map without checking top is // always safe because the limit of the heap is always aligned. if ((flags & DOUBLE_ALIGNMENT) != 0) { + ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0); ASSERT(kPointerAlignment * 2 == kDoubleAlignment); Label aligned; test(result, Immediate(kDoubleAlignmentMask)); @@ -1446,15 +1445,16 @@ void MacroAssembler::AllocateInNewSpace(Register object_size, bind(&aligned); } - // Calculate new top and bail out if new space is exhausted. - ExternalReference new_space_allocation_limit = - ExternalReference::new_space_allocation_limit_address(isolate()); + // Calculate new top and bail out if space is exhausted. + ExternalReference allocation_limit = + AllocationUtils::GetAllocationLimitReference(isolate(), flags); + if (!object_size.is(result_end)) { mov(result_end, object_size); } add(result_end, result); j(carry, gc_required); - cmp(result_end, Operand::StaticVariable(new_space_allocation_limit)); + cmp(result_end, Operand::StaticVariable(allocation_limit)); j(above, gc_required); // Tag result if requested. @@ -1511,15 +1511,15 @@ void MacroAssembler::AllocateTwoByteString(Register result, and_(scratch1, Immediate(~kObjectAlignmentMask)); // Allocate two byte string in new space. - AllocateInNewSpace(SeqTwoByteString::kHeaderSize, - times_1, - scratch1, - REGISTER_VALUE_IS_INT32, - result, - scratch2, - scratch3, - gc_required, - TAG_OBJECT); + Allocate(SeqTwoByteString::kHeaderSize, + times_1, + scratch1, + REGISTER_VALUE_IS_INT32, + result, + scratch2, + scratch3, + gc_required, + TAG_OBJECT); // Set the map, length and hash field. mov(FieldOperand(result, HeapObject::kMapOffset), @@ -1547,15 +1547,15 @@ void MacroAssembler::AllocateAsciiString(Register result, and_(scratch1, Immediate(~kObjectAlignmentMask)); // Allocate ASCII string in new space. - AllocateInNewSpace(SeqOneByteString::kHeaderSize, - times_1, - scratch1, - REGISTER_VALUE_IS_INT32, - result, - scratch2, - scratch3, - gc_required, - TAG_OBJECT); + Allocate(SeqOneByteString::kHeaderSize, + times_1, + scratch1, + REGISTER_VALUE_IS_INT32, + result, + scratch2, + scratch3, + gc_required, + TAG_OBJECT); // Set the map, length and hash field. mov(FieldOperand(result, HeapObject::kMapOffset), diff --git a/deps/v8/src/ia32/macro-assembler-ia32.h b/deps/v8/src/ia32/macro-assembler-ia32.h index 8dd412071..b3dae7320 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.h +++ b/deps/v8/src/ia32/macro-assembler-ia32.h @@ -582,22 +582,22 @@ class MacroAssembler: public Assembler { Label* gc_required, AllocationFlags flags); - void AllocateInNewSpace(int header_size, - ScaleFactor element_size, - Register element_count, - RegisterValueType element_count_type, - Register result, - Register result_end, - Register scratch, - Label* gc_required, - AllocationFlags flags); - - void AllocateInNewSpace(Register object_size, - Register result, - Register result_end, - Register scratch, - Label* gc_required, - AllocationFlags flags); + void Allocate(int header_size, + ScaleFactor element_size, + Register element_count, + RegisterValueType element_count_type, + Register result, + Register result_end, + Register scratch, + Label* gc_required, + AllocationFlags flags); + + void Allocate(Register object_size, + Register result, + Register result_end, + Register scratch, + Label* gc_required, + AllocationFlags flags); // Undo allocation in new space. The object passed and objects allocated after // it will no longer be allocated. Make sure that no pointers are left to the diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc index f7e795e78..cb4b4a731 100644 --- a/deps/v8/src/ia32/stub-cache-ia32.cc +++ b/deps/v8/src/ia32/stub-cache-ia32.cc @@ -730,7 +730,7 @@ void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm, // but may be destroyed if store is successful. void StubCompiler::GenerateStoreField(MacroAssembler* masm, Handle<JSObject> object, - int index, + LookupResult* lookup, Handle<Map> transition, Handle<Name> name, Register receiver_reg, @@ -740,16 +740,6 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, Register scratch2, Label* miss_label, Label* miss_restore_name) { - LookupResult lookup(masm->isolate()); - object->Lookup(*name, &lookup); - if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) { - // In sloppy mode, we could just return the value and be done. However, we - // might be in strict mode, where we have to throw. Since we cannot tell, - // go into slow case unconditionally. - __ jmp(miss_label); - return; - } - // Check that the map of the object hasn't changed. CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS : REQUIRE_EXACT_MAP; @@ -764,8 +754,9 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, // Check that we are allowed to write this. if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { JSObject* holder; - if (lookup.IsFound()) { - holder = lookup.holder(); + // holder == object indicates that no property was found. + if (lookup->holder() != *object) { + holder = lookup->holder(); } else { // Find the top object. holder = *object; @@ -774,8 +765,19 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, } while (holder->GetPrototype()->IsJSObject()); } // We need an extra register, push - CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg, - scratch1, scratch2, name, miss_restore_name); + Register holder_reg = CheckPrototypes( + object, receiver_reg, Handle<JSObject>(holder), name_reg, + scratch1, scratch2, name, miss_restore_name); + // If no property was found, and the holder (the last object in the + // prototype chain) is in slow mode, we need to do a negative lookup on the + // holder. + if (lookup->holder() == *object && + !holder->HasFastProperties() && + !holder->IsJSGlobalProxy() && + !holder->IsJSGlobalObject()) { + GenerateDictionaryNegativeLookup( + masm, miss_restore_name, holder_reg, name, scratch1, scratch2); + } } // Stub never generated for non-global objects that require access @@ -799,6 +801,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, return; } + int index; if (!transition.is_null()) { // Update the map of the object. __ mov(scratch1, Immediate(transition)); @@ -813,8 +816,13 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); + index = transition->instance_descriptors()->GetFieldIndex( + transition->LastAdded()); + } else { + index = lookup->GetFieldIndex().field_index(); } + // Adjust for the number of properties stored in the object. Even in the // face of a transition we can use the old map here because the size of the // object and the number of in-object properties is not going to change. @@ -2350,6 +2358,12 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object, // Check that the object is a symbol. __ CmpObjectType(edx, SYMBOL_TYPE, eax); __ j(not_equal, &miss); + // Check that the maps starting from the prototype haven't changed. + GenerateDirectLoadGlobalFunctionPrototype( + masm(), Context::SYMBOL_FUNCTION_INDEX, eax, &miss); + CheckPrototypes( + Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))), + eax, holder, ebx, edx, edi, name, &miss); break; case NUMBER_CHECK: { diff --git a/deps/v8/src/ic-inl.h b/deps/v8/src/ic-inl.h index 9439792be..ca02183db 100644 --- a/deps/v8/src/ic-inl.h +++ b/deps/v8/src/ic-inl.h @@ -109,7 +109,7 @@ InlineCacheHolderFlag IC::GetCodeCacheForObject(Object* object, // If the object is a value, we use the prototype map for the cache. ASSERT(object->IsString() || object->IsSymbol() || object->IsNumber() || object->IsBoolean()); - return DELEGATE_MAP; + return PROTOTYPE_MAP; } @@ -124,7 +124,7 @@ InlineCacheHolderFlag IC::GetCodeCacheForObject(JSObject* object, !object->HasFastProperties() && !object->IsJSGlobalProxy() && !object->IsJSGlobalObject()) { - return DELEGATE_MAP; + return PROTOTYPE_MAP; } return OWN_MAP; } @@ -133,7 +133,8 @@ InlineCacheHolderFlag IC::GetCodeCacheForObject(JSObject* object, JSObject* IC::GetCodeCacheHolder(Isolate* isolate, Object* object, InlineCacheHolderFlag holder) { - Object* map_owner = holder == OWN_MAP ? object : object->GetDelegate(isolate); + Object* map_owner = + holder == OWN_MAP ? object : object->GetPrototype(isolate); ASSERT(map_owner->IsJSObject()); return JSObject::cast(map_owner); } diff --git a/deps/v8/src/ic.cc b/deps/v8/src/ic.cc index da2211b7b..515c6f71a 100644 --- a/deps/v8/src/ic.cc +++ b/deps/v8/src/ic.cc @@ -160,7 +160,7 @@ Address IC::OriginalCodeAddress() const { // Find the function on the stack and both the active code for the // function and the original code. JSFunction* function = JSFunction::cast(frame->function()); - Handle<SharedFunctionInfo> shared(function->shared()); + Handle<SharedFunctionInfo> shared(function->shared(), isolate()); Code* code = shared->code(); ASSERT(Debug::HasDebugInfo(shared)); Code* original_code = Debug::GetDebugInfo(shared)->original_code(); @@ -190,7 +190,7 @@ static bool TryRemoveInvalidPrototypeDependentStub(Code* target, // The stub was generated for JSObject but called for non-JSObject. // IC::GetCodeCacheHolder is not applicable. return false; - } else if (cache_holder == DELEGATE_MAP && + } else if (cache_holder == PROTOTYPE_MAP && receiver->GetPrototype(isolate)->IsNull()) { // IC::GetCodeCacheHolder is not applicable. return false; @@ -435,7 +435,7 @@ static void LookupForRead(Handle<Object> object, return; } - Handle<JSObject> holder(lookup->holder()); + Handle<JSObject> holder(lookup->holder(), lookup->isolate()); if (HasInterceptorGetter(*holder)) { return; } @@ -446,7 +446,7 @@ static void LookupForRead(Handle<Object> object, return; } - Handle<Object> proto(holder->GetPrototype(), name->GetIsolate()); + Handle<Object> proto(holder->GetPrototype(), lookup->isolate()); if (proto->IsNull()) { ASSERT(!lookup->IsFound()); return; @@ -636,7 +636,7 @@ Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup, Handle<Object> object, Handle<String> name) { int argc = target()->arguments_count(); - Handle<JSObject> holder(lookup->holder()); + Handle<JSObject> holder(lookup->holder(), isolate()); switch (lookup->type()) { case FIELD: { PropertyIndex index = lookup->GetFieldIndex(); @@ -647,7 +647,7 @@ Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup, // Get the constant function and compute the code stub for this // call; used for rewriting to monomorphic state and making sure // that the code stub is in the stub cache. - Handle<JSFunction> function(lookup->GetConstantFunction()); + Handle<JSFunction> function(lookup->GetConstantFunction(), isolate()); return isolate()->stub_cache()->ComputeCallConstant( argc, kind_, extra_state, name, object, holder, function); } @@ -658,7 +658,8 @@ Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup, if (holder->IsGlobalObject()) { Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); - Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); + Handle<JSGlobalPropertyCell> cell( + global->GetPropertyCell(lookup), isolate()); if (!cell->value()->IsJSFunction()) return Handle<Code>::null(); Handle<JSFunction> function(JSFunction::cast(cell->value())); return isolate()->stub_cache()->ComputeCallGlobal( @@ -746,7 +747,8 @@ void CallICBase::UpdateCaches(LookupResult* lookup, // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. Handle<JSObject> cache_object = object->IsJSObject() ? Handle<JSObject>::cast(object) - : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))); + : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())), + isolate()); // Update the stub cache. UpdateMegamorphicCache(cache_object->map(), *name, *code); break; @@ -855,28 +857,6 @@ MaybeObject* LoadIC::Load(State state, return Smi::FromInt(String::cast(*string)->length()); } - // Use specialized code for getting the length of arrays. - if (object->IsJSArray() && - name->Equals(isolate()->heap()->length_string())) { - Handle<Code> stub; - if (state == UNINITIALIZED) { - stub = pre_monomorphic_stub(); - } else if (state == PREMONOMORPHIC) { - ArrayLengthStub array_length_stub(kind()); - stub = array_length_stub.GetCode(isolate()); - } else if (state != MEGAMORPHIC) { - ASSERT(state != GENERIC); - stub = megamorphic_stub(); - } - if (!stub.is_null()) { - set_target(*stub); -#ifdef DEBUG - if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); -#endif - } - return JSArray::cast(*object)->length(); - } - // Use specialized code for getting prototype of functions. if (object->IsJSFunction() && name->Equals(isolate()->heap()->prototype_string()) && @@ -1035,6 +1015,22 @@ void IC::CopyICToMegamorphicCache(Handle<String> name) { } +bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) { + AssertNoAllocation no_allocation; + + Map* current_map = target()->FindFirstMap(); + ElementsKind receiver_elements_kind = receiver_map->elements_kind(); + bool more_general_transition = + IsMoreGeneralElementsKindTransition( + current_map->elements_kind(), receiver_elements_kind); + Map* transitioned_map = more_general_transition + ? current_map->LookupElementsTransitionMap(receiver_elements_kind) + : NULL; + + return transitioned_map == receiver_map; +} + + // Since GC may have been invoked, by the time PatchCache is called, |state| is // not necessarily equal to target()->state(). void IC::PatchCache(State state, @@ -1052,6 +1048,17 @@ void IC::PatchCache(State state, // Only move to megamorphic if the target changes. if (target() != *code) { if (target()->is_load_stub()) { + bool is_same_handler = false; + { + AssertNoAllocation no_allocation; + Code* old_handler = target()->FindFirstCode(); + is_same_handler = old_handler == *code; + } + if (is_same_handler + && IsTransitionedMapOfMonomorphicTarget(receiver->map())) { + UpdateMonomorphicIC(receiver, code, name); + break; + } if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) { break; } @@ -1196,7 +1203,8 @@ Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup, case NORMAL: if (holder->IsGlobalObject()) { Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); - Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); + Handle<JSGlobalPropertyCell> cell( + global->GetPropertyCell(lookup), isolate()); return isolate()->stub_cache()->ComputeLoadGlobal( name, receiver, global, cell, lookup->IsDontDelete()); } @@ -1223,6 +1231,12 @@ Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup, if (!holder->HasFastProperties()) break; return isolate()->stub_cache()->ComputeLoadViaGetter( name, receiver, holder, Handle<JSFunction>::cast(getter)); + } else if (receiver->IsJSArray() && + name->Equals(isolate()->heap()->length_string())) { + PropertyIndex lengthIndex = + PropertyIndex::NewHeaderIndex(JSArray::kLengthOffset / kPointerSize); + return isolate()->stub_cache()->ComputeLoadField( + name, receiver, holder, lengthIndex); } // TODO(dcarney): Handle correctly. if (callback->IsDeclaredAccessorInfo()) break; @@ -1272,7 +1286,7 @@ Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) { return generic_stub(); } - Handle<Map> receiver_map(receiver->map()); + Handle<Map> receiver_map(receiver->map(), isolate()); MapHandleList target_receiver_maps; if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { // Optimistically assume that ICs that haven't reached the MONOMORPHIC state @@ -1283,7 +1297,8 @@ Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) { if (target() == *string_stub()) { target_receiver_maps.Add(isolate()->factory()->string_map()); } else { - GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps); + GetReceiverMapsForStub(Handle<Code>(target(), isolate()), + &target_receiver_maps); if (target_receiver_maps.length() == 0) { return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map); } @@ -1355,7 +1370,8 @@ MaybeObject* KeyedLoadIC::Load(State state, stub = non_strict_arguments_stub(); } else if (receiver->HasIndexedInterceptor()) { stub = indexed_interceptor_stub(); - } else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) { + } else if (!key->ToSmi()->IsFailure() && + (target() != *non_strict_arguments_stub())) { stub = LoadElementStub(receiver); } } @@ -1379,13 +1395,13 @@ Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup, if (!lookup->IsProperty()) return Handle<Code>::null(); // Compute a monomorphic stub. - Handle<JSObject> holder(lookup->holder()); + Handle<JSObject> holder(lookup->holder(), isolate()); switch (lookup->type()) { case FIELD: return isolate()->stub_cache()->ComputeKeyedLoadField( name, receiver, holder, lookup->GetFieldIndex()); case CONSTANT_FUNCTION: { - Handle<JSFunction> constant(lookup->GetConstantFunction()); + Handle<JSFunction> constant(lookup->GetConstantFunction(), isolate()); return isolate()->stub_cache()->ComputeKeyedLoadConstant( name, receiver, holder, constant); } @@ -1413,41 +1429,42 @@ Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup, } -static bool StoreICableLookup(LookupResult* lookup) { - // Bail out if we didn't find a result. - if (!lookup->IsFound()) return false; - - // Bail out if inline caching is not allowed. - if (!lookup->IsCacheable()) return false; - - // If the property is read-only, we leave the IC in its current state. - if (lookup->IsTransition()) { - return !lookup->GetTransitionDetails().IsReadOnly(); - } - return !lookup->IsReadOnly(); -} - - static bool LookupForWrite(Handle<JSObject> receiver, Handle<String> name, LookupResult* lookup) { - receiver->LocalLookup(*name, lookup); - if (!lookup->IsFound()) { - receiver->map()->LookupTransition(*receiver, *name, lookup); - } - if (!StoreICableLookup(lookup)) { - // 2nd chance: There can be accessors somewhere in the prototype chain. - receiver->Lookup(*name, lookup); - return lookup->IsPropertyCallbacks() && StoreICableLookup(lookup); - } + Handle<JSObject> holder = receiver; + receiver->Lookup(*name, lookup); + if (lookup->IsFound()) { + if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; + + if (lookup->holder() == *receiver) { + if (lookup->IsInterceptor() && + receiver->GetNamedInterceptor()->setter()->IsUndefined()) { + receiver->LocalLookupRealNamedProperty(*name, lookup); + return lookup->IsFound() && + !lookup->IsReadOnly() && + lookup->IsCacheable(); + } + return true; + } - if (lookup->IsInterceptor() && - receiver->GetNamedInterceptor()->setter()->IsUndefined()) { - receiver->LocalLookupRealNamedProperty(*name, lookup); - return StoreICableLookup(lookup); + if (lookup->IsPropertyCallbacks()) return true; + + // Currently normal holders in the prototype chain are not supported. They + // would require a runtime positive lookup and verification that the details + // have not changed. + if (lookup->IsInterceptor() || lookup->IsNormal()) return false; + holder = Handle<JSObject>(lookup->holder(), lookup->isolate()); } - return true; + // While normally LookupTransition gets passed the receiver, in this case we + // pass the holder of the property that we overwrite. This keeps the holder in + // the LookupResult intact so we can later use it to generate a prototype + // chain check. This avoids a double lookup, but requires us to pass in the + // receiver when trying to fetch extra information from the transition. + receiver->map()->LookupTransition(*holder, *name, lookup); + return lookup->IsTransition() && + !lookup->GetTransitionDetails(receiver->map()).IsReadOnly(); } @@ -1547,7 +1564,6 @@ void StoreIC::UpdateCaches(LookupResult* lookup, Handle<String> name, Handle<Object> value) { ASSERT(!receiver->IsJSGlobalProxy()); - ASSERT(StoreICableLookup(lookup)); ASSERT(lookup->IsFound()); // These are not cacheable, so we never see such LookupResults here. @@ -1570,19 +1586,19 @@ Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup, switch (lookup->type()) { case FIELD: return isolate()->stub_cache()->ComputeStoreField( - name, receiver, lookup->GetFieldIndex().field_index(), - Handle<Map>::null(), strict_mode); + name, receiver, lookup, Handle<Map>::null(), strict_mode); case NORMAL: if (receiver->IsGlobalObject()) { // The stub generated for the global object picks the value directly // from the property cell. So the property must be directly on the // global object. Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); - Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); + Handle<JSGlobalPropertyCell> cell( + global->GetPropertyCell(lookup), isolate()); return isolate()->stub_cache()->ComputeStoreGlobal( name, global, cell, strict_mode); } - if (!holder.is_identical_to(receiver)) break; + ASSERT(holder.is_identical_to(receiver)); return isolate()->stub_cache()->ComputeStoreNormal(strict_mode); case CALLBACKS: { Handle<Object> callback(lookup->GetCallbackObject(), isolate()); @@ -1595,8 +1611,8 @@ Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup, return isolate()->stub_cache()->ComputeStoreCallback( name, receiver, holder, info, strict_mode); } else if (callback->IsAccessorPair()) { - Handle<Object> setter(Handle<AccessorPair>::cast(callback)->setter(), - isolate()); + Handle<Object> setter( + Handle<AccessorPair>::cast(callback)->setter(), isolate()); if (!setter->IsJSFunction()) break; if (holder->IsGlobalObject()) break; if (!holder->HasFastProperties()) break; @@ -1617,7 +1633,10 @@ Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup, case CONSTANT_FUNCTION: break; case TRANSITION: { - Handle<Map> transition(lookup->GetTransitionTarget()); + // Explicitly pass in the receiver map since LookupForWrite may have + // stored something else than the receiver in the holder. + Handle<Map> transition( + lookup->GetTransitionTarget(receiver->map()), isolate()); int descriptor = transition->LastAdded(); DescriptorArray* target_descriptors = transition->instance_descriptors(); @@ -1625,9 +1644,8 @@ Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup, if (details.type() != FIELD || details.attributes() != NONE) break; - int field_index = target_descriptors->GetFieldIndex(descriptor); return isolate()->stub_cache()->ComputeStoreField( - name, receiver, field_index, transition, strict_mode); + name, receiver, lookup, transition, strict_mode); } case NONEXISTENT: case HANDLER: @@ -1649,7 +1667,8 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub(); } - if ((store_mode == STORE_NO_TRANSITION_HANDLE_COW || + if (!FLAG_compiled_keyed_stores && + (store_mode == STORE_NO_TRANSITION_HANDLE_COW || store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS)) { // TODO(danno): We'll soon handle MONOMORPHIC ICs that also support // copying COW arrays and silently ignoring some OOB stores into external @@ -1661,7 +1680,7 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, } State ic_state = target()->ic_state(); - Handle<Map> receiver_map(receiver->map()); + Handle<Map> receiver_map(receiver->map(), isolate()); if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { // Optimistically assume that ICs that haven't reached the MONOMORPHIC state // yet will do so and stay there. @@ -1697,24 +1716,18 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, transitioned_receiver_map = ComputeTransitionedMap(receiver, store_mode); } - ElementsKind transitioned_kind = - transitioned_receiver_map->elements_kind(); - bool more_general_transition = - IsMoreGeneralElementsKindTransition( - previous_receiver_map->elements_kind(), - transitioned_kind); - Map* transitioned_previous_map = more_general_transition - ? previous_receiver_map->LookupElementsTransitionMap(transitioned_kind) - : NULL; - if (transitioned_previous_map == *transitioned_receiver_map) { + if (IsTransitionedMapOfMonomorphicTarget(*transitioned_receiver_map)) { // Element family is the same, use the "worst" case map. store_mode = GetNonTransitioningStoreMode(store_mode); return isolate()->stub_cache()->ComputeKeyedStoreElement( transitioned_receiver_map, strict_mode, store_mode); } else if (*previous_receiver_map == receiver->map()) { - if (IsGrowStoreMode(store_mode)) { + if (IsGrowStoreMode(store_mode) || + store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || + store_mode == STORE_NO_TRANSITION_HANDLE_COW) { // A "normal" IC that handles stores can switch to a version that can - // grow at the end of the array and still stay MONOMORPHIC. + // grow at the end of the array, handle OOB accesses or copy COW arrays + // and still stay MONOMORPHIC. return isolate()->stub_cache()->ComputeKeyedStoreElement( receiver_map, strict_mode, store_mode); } @@ -1761,6 +1774,26 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, } } + // If the store mode isn't the standard mode, make sure that all polymorphic + // receivers are either external arrays, or all "normal" arrays. Otherwise, + // use the generic stub. + if (store_mode != STANDARD_STORE) { + int external_arrays = 0; + for (int i = 0; i < target_receiver_maps.length(); ++i) { + if (target_receiver_maps[i]->has_external_array_elements()) { + external_arrays++; + } + } + if (external_arrays != 0 && + external_arrays != target_receiver_maps.length()) { + TRACE_GENERIC_IC(isolate(), "KeyedIC", + "unsupported combination of external and normal arrays"); + return strict_mode == kStrictMode + ? generic_stub_strict() + : generic_stub(); + } + } + return isolate()->stub_cache()->ComputeStoreElementPolymorphic( &target_receiver_maps, store_mode, strict_mode); } @@ -1794,7 +1827,7 @@ Handle<Map> KeyedStoreIC::ComputeTransitionedMap( case STORE_NO_TRANSITION_HANDLE_COW: case STANDARD_STORE: case STORE_AND_GROW_NO_TRANSITION: - return Handle<Map>(receiver->map()); + return Handle<Map>(receiver->map(), isolate()); } return Handle<Map>::null(); } @@ -1813,8 +1846,10 @@ bool IsOutOfBoundsAccess(Handle<JSObject> receiver, KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver, Handle<Object> key, Handle<Object> value) { - ASSERT(key->IsSmi()); - int index = Smi::cast(*key)->value(); + ASSERT(!key->ToSmi()->IsFailure()); + Smi* smi_key = NULL; + key->ToSmi()->To(&smi_key); + int index = smi_key->value(); bool oob_access = IsOutOfBoundsAccess(receiver, index); bool allow_growth = receiver->IsJSArray() && oob_access; if (allow_growth) { @@ -1872,6 +1907,10 @@ KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver, if (!FLAG_trace_external_array_abuse && receiver->map()->has_external_array_elements() && oob_access) { return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS; + } + Heap* heap = receiver->GetHeap(); + if (receiver->elements()->map() == heap->fixed_cow_array_map()) { + return STORE_NO_TRANSITION_HANDLE_COW; } else { return STANDARD_STORE; } @@ -1910,13 +1949,20 @@ MaybeObject* KeyedStoreIC::Store(State state, if (miss_mode != MISS_FORCE_GENERIC) { if (object->IsJSObject()) { Handle<JSObject> receiver = Handle<JSObject>::cast(object); + bool key_is_smi_like = key->IsSmi() || + (FLAG_compiled_keyed_stores && !key->ToSmi()->IsFailure()); if (receiver->elements()->map() == isolate()->heap()->non_strict_arguments_elements_map()) { stub = non_strict_arguments_stub(); - } else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) { + } else if (key_is_smi_like && + (target() != *non_strict_arguments_stub())) { KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value); stub = StoreElementStub(receiver, store_mode, strict_mode); + } else { + TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "key not a number"); } + } else { + TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "not an object"); } } else { TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "force generic"); @@ -1941,19 +1987,20 @@ Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup, switch (lookup->type()) { case FIELD: return isolate()->stub_cache()->ComputeKeyedStoreField( - name, receiver, lookup->GetFieldIndex().field_index(), - Handle<Map>::null(), strict_mode); + name, receiver, lookup, Handle<Map>::null(), strict_mode); case TRANSITION: { - Handle<Map> transition(lookup->GetTransitionTarget()); + // Explicitly pass in the receiver map since LookupForWrite may have + // stored something else than the receiver in the holder. + Handle<Map> transition( + lookup->GetTransitionTarget(receiver->map()), isolate()); int descriptor = transition->LastAdded(); DescriptorArray* target_descriptors = transition->instance_descriptors(); PropertyDetails details = target_descriptors->GetDetails(descriptor); if (details.type() == FIELD && details.attributes() == NONE) { - int field_index = target_descriptors->GetFieldIndex(descriptor); return isolate()->stub_cache()->ComputeKeyedStoreField( - name, receiver, field_index, transition, strict_mode); + name, receiver, lookup, transition, strict_mode); } // fall through. } @@ -2023,7 +2070,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) { if (raw_function->is_compiled()) return raw_function; - Handle<JSFunction> function(raw_function); + Handle<JSFunction> function(raw_function, isolate); JSFunction::CompileLazy(function, CLEAR_EXCEPTION); return *function; } @@ -2074,7 +2121,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) { RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { HandleScope scope(isolate); ASSERT(args.length() == 3); - StoreIC ic(isolate); + StoreIC ic(IC::NO_EXTRA_FRAME, isolate); IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); return ic.Store(state, @@ -2150,7 +2197,22 @@ RUNTIME_FUNCTION(MaybeObject*, SharedStoreIC_ExtendStorage) { RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) { HandleScope scope(isolate); ASSERT(args.length() == 3); - KeyedStoreIC ic(isolate); + KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); + IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); + Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); + return ic.Store(state, + Code::GetStrictMode(extra_ic_state), + args.at<Object>(0), + args.at<Object>(1), + args.at<Object>(2), + MISS); +} + + +RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure) { + HandleScope scope(isolate); + ASSERT(args.length() == 3); + KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); return ic.Store(state, @@ -2165,7 +2227,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) { RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) { NoHandleAllocation na(isolate); ASSERT(args.length() == 3); - KeyedStoreIC ic(isolate); + KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); Handle<Object> object = args.at<Object>(0); Handle<Object> key = args.at<Object>(1); @@ -2183,7 +2245,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) { RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) { HandleScope scope(isolate); ASSERT(args.length() == 3); - KeyedStoreIC ic(isolate); + KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); return ic.Store(state, @@ -2668,7 +2730,8 @@ void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { HasInlinedSmiCode(address()), x, y); ICCompareStub stub(op_, new_left, new_right, state); if (state == KNOWN_OBJECT) { - stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map())); + stub.set_known_map( + Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate())); } set_target(*stub.GetCode(isolate())); diff --git a/deps/v8/src/ic.h b/deps/v8/src/ic.h index b22595552..55b566192 100644 --- a/deps/v8/src/ic.h +++ b/deps/v8/src/ic.h @@ -176,6 +176,7 @@ class IC { Handle<String> name, Handle<Code> code); void CopyICToMegamorphicCache(Handle<String> name); + bool IsTransitionedMapOfMonomorphicTarget(Map* receiver_map); void PatchCache(State state, StrictModeFlag strict_mode, Handle<JSObject> receiver, @@ -496,7 +497,7 @@ class KeyedLoadIC: public LoadIC { class StoreIC: public IC { public: - explicit StoreIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { + StoreIC(FrameDepth depth, Isolate* isolate) : IC(depth, isolate) { ASSERT(target()->is_store_stub() || target()->is_keyed_store_stub()); } @@ -585,7 +586,8 @@ enum KeyedStoreIncrementLength { class KeyedStoreIC: public StoreIC { public: - explicit KeyedStoreIC(Isolate* isolate) : StoreIC(isolate) { + KeyedStoreIC(FrameDepth depth, Isolate* isolate) + : StoreIC(depth, isolate) { ASSERT(target()->is_keyed_store_stub()); } @@ -786,6 +788,7 @@ enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK }; void PatchInlinedSmiCode(Address address, InlinedSmiCheck check); DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure); +DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure); } } // namespace v8::internal diff --git a/deps/v8/src/interpreter-irregexp.cc b/deps/v8/src/interpreter-irregexp.cc index 5abeb5a10..e678e6cf1 100644 --- a/deps/v8/src/interpreter-irregexp.cc +++ b/deps/v8/src/interpreter-irregexp.cc @@ -73,9 +73,15 @@ static bool BackRefMatchesNoCase(Canonicalize* interp_canonicalize, unsigned int old_char = subject[from++]; unsigned int new_char = subject[current++]; if (old_char == new_char) continue; - if (old_char - 'A' <= 'Z' - 'A') old_char |= 0x20; - if (new_char - 'A' <= 'Z' - 'A') new_char |= 0x20; + // Convert both characters to lower case. + old_char |= 0x20; + new_char |= 0x20; if (old_char != new_char) return false; + // Not letters in the ASCII range and Latin-1 range. + if (!(old_char - 'a' <= 'z' - 'a') && + !(old_char - 224 <= 254 - 224 && old_char != 247)) { + return false; + } } return true; } diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc index 5d4bc89b9..04155195a 100644 --- a/deps/v8/src/isolate.cc +++ b/deps/v8/src/isolate.cc @@ -612,13 +612,16 @@ Handle<JSArray> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object, limit = Max(limit, 0); // Ensure that limit is not negative. int initial_size = Min(limit, 10); Handle<FixedArray> elements = - factory()->NewFixedArrayWithHoles(initial_size * 4); + factory()->NewFixedArrayWithHoles(initial_size * 4 + 1); // If the caller parameter is a function we skip frames until we're // under it before starting to collect. bool seen_caller = !caller->IsJSFunction(); - int cursor = 0; + // First element is reserved to store the number of non-strict frames. + int cursor = 1; int frames_seen = 0; + int non_strict_frames = 0; + bool encountered_strict_function = false; for (StackFrameIterator iter(this); !iter.done() && frames_seen < limit; iter.Advance()) { @@ -646,6 +649,17 @@ Handle<JSArray> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object, Handle<JSFunction> fun = frames[i].function(); Handle<Code> code = frames[i].code(); Handle<Smi> offset(Smi::FromInt(frames[i].offset()), this); + // The stack trace API should not expose receivers and function + // objects on frames deeper than the top-most one with a strict + // mode function. The number of non-strict frames is stored as + // first element in the result array. + if (!encountered_strict_function) { + if (!fun->shared()->is_classic_mode()) { + encountered_strict_function = true; + } else { + non_strict_frames++; + } + } elements->set(cursor++, *recv); elements->set(cursor++, *fun); elements->set(cursor++, *code); @@ -653,6 +667,7 @@ Handle<JSArray> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object, } } } + elements->set(0, Smi::FromInt(non_strict_frames)); Handle<JSArray> result = factory()->NewJSArrayWithElements(elements); result->set_length(Smi::FromInt(cursor)); return result; @@ -1679,6 +1694,7 @@ Isolate::Isolate() code_stub_interface_descriptors_(NULL), context_exit_happened_(false), cpu_profiler_(NULL), + heap_profiler_(NULL), deferred_handles_head_(NULL), optimizing_compiler_thread_(this), marking_thread_(NULL), @@ -1810,7 +1826,8 @@ void Isolate::Deinit() { preallocated_message_space_ = NULL; PreallocatedMemoryThreadStop(); - HeapProfiler::TearDown(); + delete heap_profiler_; + heap_profiler_ = NULL; delete cpu_profiler_; cpu_profiler_ = NULL; @@ -2043,7 +2060,7 @@ bool Isolate::Init(Deserializer* des) { logger_->SetUp(); cpu_profiler_ = new CpuProfiler(this); - HeapProfiler::SetUp(); + heap_profiler_ = new HeapProfiler(heap()); // Initialize other runtime facilities #if defined(USE_SIMULATOR) diff --git a/deps/v8/src/isolate.h b/deps/v8/src/isolate.h index ad0b260bc..f7a81d30d 100644 --- a/deps/v8/src/isolate.h +++ b/deps/v8/src/isolate.h @@ -368,7 +368,6 @@ typedef List<HeapObject*, PreallocatedStorageAllocationPolicy> DebugObjectCache; V(unsigned, ast_node_count, 0) \ /* SafeStackFrameIterator activations count. */ \ V(int, safe_stack_iterator_counter, 0) \ - V(HeapProfiler*, heap_profiler, NULL) \ V(bool, observer_delivery_pending, false) \ V(HStatistics*, hstatistics, NULL) \ V(HTracer*, htracer, NULL) \ @@ -976,6 +975,7 @@ class Isolate { inline bool DebuggerHasBreakPoints(); CpuProfiler* cpu_profiler() const { return cpu_profiler_; } + HeapProfiler* heap_profiler() const { return heap_profiler_; } #ifdef DEBUG HistogramInfo* heap_histograms() { return heap_histograms_; } @@ -1313,6 +1313,7 @@ class Isolate { Debug* debug_; #endif CpuProfiler* cpu_profiler_; + HeapProfiler* heap_profiler_; #define GLOBAL_BACKING_STORE(type, name, initialvalue) \ type name##_; diff --git a/deps/v8/src/json-parser.h b/deps/v8/src/json-parser.h index 28ef8b33c..ac34c59b2 100644 --- a/deps/v8/src/json-parser.h +++ b/deps/v8/src/json-parser.h @@ -291,6 +291,7 @@ Handle<Object> JsonParser<seq_ascii>::ParseJsonValue() { // Parse a JSON object. Position must be right at '{'. template <bool seq_ascii> Handle<Object> JsonParser<seq_ascii>::ParseJsonObject() { + HandleScope scope(isolate()); Handle<JSObject> json_object = factory()->NewJSObject(object_constructor(), pretenure_); ASSERT_EQ(c0_, '{'); @@ -358,12 +359,13 @@ Handle<Object> JsonParser<seq_ascii>::ParseJsonObject() { } } AdvanceSkipWhitespace(); - return json_object; + return scope.CloseAndEscape(json_object); } // Parse a JSON array. Position must be right at '['. template <bool seq_ascii> Handle<Object> JsonParser<seq_ascii>::ParseJsonArray() { + HandleScope scope(isolate()); ZoneScope zone_scope(zone(), DELETE_ON_EXIT); ZoneList<Handle<Object> > elements(4, zone()); ASSERT_EQ(c0_, '['); @@ -386,8 +388,9 @@ Handle<Object> JsonParser<seq_ascii>::ParseJsonArray() { for (int i = 0, n = elements.length(); i < n; i++) { fast_elements->set(i, *elements[i]); } - return factory()->NewJSArrayWithElements( + Handle<Object> json_array = factory()->NewJSArrayWithElements( fast_elements, FAST_ELEMENTS, pretenure_); + return scope.CloseAndEscape(json_array); } @@ -501,10 +504,10 @@ Handle<String> JsonParser<seq_ascii>::SlowScanJsonString( int count = end - start; int max_length = count + source_length_ - position_; int length = Min(max_length, Max(kInitialSpecialStringLength, 2 * count)); - Handle<StringType> seq_str = + Handle<StringType> seq_string = NewRawString<StringType>(factory(), length, pretenure_); // Copy prefix into seq_str. - SinkChar* dest = seq_str->GetChars(); + SinkChar* dest = seq_string->GetChars(); String::WriteToFlat(*prefix, dest, start, end); while (c0_ != '"') { @@ -512,7 +515,7 @@ Handle<String> JsonParser<seq_ascii>::SlowScanJsonString( if (c0_ < 0x20) return Handle<String>::null(); if (count >= length) { // We need to create a longer sequential string for the result. - return SlowScanJsonString<StringType, SinkChar>(seq_str, 0, count); + return SlowScanJsonString<StringType, SinkChar>(seq_string, 0, count); } if (c0_ != '\\') { // If the sink can contain UC16 characters, or source_ contains only @@ -522,11 +525,11 @@ Handle<String> JsonParser<seq_ascii>::SlowScanJsonString( if (sizeof(SinkChar) == kUC16Size || seq_ascii || c0_ <= String::kMaxOneByteCharCode) { - SeqStringSet(seq_str, count++, c0_); + SeqStringSet(seq_string, count++, c0_); Advance(); } else { // StringType is SeqOneByteString and we just read a non-ASCII char. - return SlowScanJsonString<SeqTwoByteString, uc16>(seq_str, 0, count); + return SlowScanJsonString<SeqTwoByteString, uc16>(seq_string, 0, count); } } else { Advance(); // Advance past the \. @@ -534,22 +537,22 @@ Handle<String> JsonParser<seq_ascii>::SlowScanJsonString( case '"': case '\\': case '/': - SeqStringSet(seq_str, count++, c0_); + SeqStringSet(seq_string, count++, c0_); break; case 'b': - SeqStringSet(seq_str, count++, '\x08'); + SeqStringSet(seq_string, count++, '\x08'); break; case 'f': - SeqStringSet(seq_str, count++, '\x0c'); + SeqStringSet(seq_string, count++, '\x0c'); break; case 'n': - SeqStringSet(seq_str, count++, '\x0a'); + SeqStringSet(seq_string, count++, '\x0a'); break; case 'r': - SeqStringSet(seq_str, count++, '\x0d'); + SeqStringSet(seq_string, count++, '\x0d'); break; case 't': - SeqStringSet(seq_str, count++, '\x09'); + SeqStringSet(seq_string, count++, '\x09'); break; case 'u': { uc32 value = 0; @@ -563,13 +566,13 @@ Handle<String> JsonParser<seq_ascii>::SlowScanJsonString( } if (sizeof(SinkChar) == kUC16Size || value <= String::kMaxOneByteCharCode) { - SeqStringSet(seq_str, count++, value); + SeqStringSet(seq_string, count++, value); break; } else { // StringType is SeqOneByteString and we just read a non-ASCII char. position_ -= 6; // Rewind position_ to \ in \uxxxx. Advance(); - return SlowScanJsonString<SeqTwoByteString, uc16>(seq_str, + return SlowScanJsonString<SeqTwoByteString, uc16>(seq_string, 0, count); } @@ -580,23 +583,13 @@ Handle<String> JsonParser<seq_ascii>::SlowScanJsonString( Advance(); } } - // Shrink seq_string length to count. - if (isolate()->heap()->InNewSpace(*seq_str)) { - isolate()->heap()->new_space()-> - template ShrinkStringAtAllocationBoundary<StringType>( - *seq_str, count); - } else { - int string_size = StringType::SizeFor(count); - int allocated_string_size = StringType::SizeFor(length); - int delta = allocated_string_size - string_size; - Address start_filler_object = seq_str->address() + string_size; - seq_str->set_length(count); - isolate()->heap()->CreateFillerObjectAt(start_filler_object, delta); - } + ASSERT_EQ('"', c0_); // Advance past the last '"'. AdvanceSkipWhitespace(); - return seq_str; + + // Shrink seq_string length to count and return. + return SeqString::Truncate(seq_string, count); } @@ -623,8 +616,8 @@ Handle<String> JsonParser<seq_ascii>::ScanJsonString() { int beg_pos = position_; position_ = position; return SlowScanJsonString<SeqOneByteString, uint8_t>(source_, - beg_pos, - position_); + beg_pos, + position_); } if (c0 < 0x20) return Handle<String>::null(); if (static_cast<uint32_t>(c0) > diff --git a/deps/v8/src/json-stringifier.h b/deps/v8/src/json-stringifier.h index ad9ef3ddb..bcdd64ce7 100644 --- a/deps/v8/src/json-stringifier.h +++ b/deps/v8/src/json-stringifier.h @@ -41,6 +41,9 @@ class BasicJsonStringifier BASE_EMBEDDED { MaybeObject* Stringify(Handle<Object> object); + INLINE(static MaybeObject* StringifyString(Isolate* isolate, + Handle<String> object)); + private: static const int kInitialPartLength = 32; static const int kMaxPartLength = 16 * 1024; @@ -52,7 +55,7 @@ class BasicJsonStringifier BASE_EMBEDDED { void ChangeEncoding(); - void ShrinkCurrentPart(); + INLINE(void ShrinkCurrentPart()); template <bool is_ascii, typename Char> INLINE(void Append_(Char c)); @@ -84,6 +87,11 @@ class BasicJsonStringifier BASE_EMBEDDED { bool deferred_comma, bool deferred_key); + template <typename ResultType, typename Char> + INLINE(static MaybeObject* StringifyString_(Isolate* isolate, + Vector<Char> vector, + Handle<String> result)); + // Entry point to serialize the object. INLINE(Result SerializeObject(Handle<Object> obj)) { return Serialize_<false>(obj, false, factory_->empty_string()); @@ -135,18 +143,18 @@ class BasicJsonStringifier BASE_EMBEDDED { void SerializeString(Handle<String> object); template <typename SrcChar, typename DestChar> - INLINE(void SerializeStringUnchecked_(const SrcChar* src, - DestChar* dest, - int length)); + INLINE(static int SerializeStringUnchecked_(const SrcChar* src, + DestChar* dest, + int length)); template <bool is_ascii, typename Char> INLINE(void SerializeString_(Handle<String> string)); template <typename Char> - INLINE(bool DoNotEscape(Char c)); + INLINE(static bool DoNotEscape(Char c)); template <typename Char> - INLINE(Vector<const Char> GetCharVector(Handle<String> string)); + INLINE(static Vector<const Char> GetCharVector(Handle<String> string)); Result StackPush(Handle<Object> object); void StackPop(); @@ -244,15 +252,15 @@ const char* const BasicJsonStringifier::JsonEscapeTable = "\370\0 \371\0 \372\0 \373\0 " "\374\0 \375\0 \376\0 \377\0 "; + BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate) : isolate_(isolate), current_index_(0), is_ascii_(true) { factory_ = isolate_->factory(); accumulator_store_ = Handle<JSValue>::cast( factory_->ToObject(factory_->empty_string())); part_length_ = kInitialPartLength; - current_part_ = factory_->NewRawOneByteString(kInitialPartLength); - tojson_string_ = - factory_->InternalizeOneByteString(STATIC_ASCII_VECTOR("toJSON")); + current_part_ = factory_->NewRawOneByteString(part_length_); + tojson_string_ = factory_->toJSON_string(); stack_ = factory_->NewJSArray(8); } @@ -275,6 +283,51 @@ MaybeObject* BasicJsonStringifier::Stringify(Handle<Object> object) { } +MaybeObject* BasicJsonStringifier::StringifyString(Isolate* isolate, + Handle<String> object) { + static const int kJsonQuoteWorstCaseBlowup = 6; + static const int kSpaceForQuotes = 2; + int worst_case_length = + object->length() * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes; + + if (worst_case_length > 32 * KB) { // Slow path if too large. + BasicJsonStringifier stringifier(isolate); + return stringifier.Stringify(object); + } + + FlattenString(object); + String::FlatContent flat = object->GetFlatContent(); + if (flat.IsAscii()) { + return StringifyString_<SeqOneByteString>( + isolate, + flat.ToOneByteVector(), + isolate->factory()->NewRawOneByteString(worst_case_length)); + } else { + ASSERT(flat.IsTwoByte()); + return StringifyString_<SeqTwoByteString>( + isolate, + flat.ToUC16Vector(), + isolate->factory()->NewRawTwoByteString(worst_case_length)); + } +} + + +template <typename ResultType, typename Char> +MaybeObject* BasicJsonStringifier::StringifyString_(Isolate* isolate, + Vector<Char> vector, + Handle<String> result) { + AssertNoAllocation no_allocation; + int final_size = 0; + ResultType* dest = ResultType::cast(*result); + dest->Set(final_size++, '\"'); + final_size += SerializeStringUnchecked_(vector.start(), + dest->GetChars() + 1, + vector.length()); + dest->Set(final_size++, '\"'); + return *SeqString::Truncate(Handle<SeqString>::cast(result), final_size); +} + + template <bool is_ascii, typename Char> void BasicJsonStringifier::Append_(Char c) { if (is_ascii) { @@ -638,8 +691,8 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( void BasicJsonStringifier::ShrinkCurrentPart() { ASSERT(current_index_ < part_length_); - current_part_ = Handle<String>( - SeqString::cast(*current_part_)->Truncate(current_index_), isolate_); + current_part_ = SeqString::Truncate(Handle<SeqString>::cast(current_part_), + current_index_); } @@ -667,10 +720,9 @@ void BasicJsonStringifier::ChangeEncoding() { template <typename SrcChar, typename DestChar> -void BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src, - DestChar* dest, - int length) { - dest += current_index_; +int BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src, + DestChar* dest, + int length) { DestChar* dest_start = dest; // Assert that uc16 character is not truncated down to 8 bit. @@ -688,7 +740,7 @@ void BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src, } } - current_index_ += static_cast<int>(dest - dest_start); + return static_cast<int>(dest - dest_start); } @@ -705,14 +757,14 @@ void BasicJsonStringifier::SerializeString_(Handle<String> string) { AssertNoAllocation no_allocation; Vector<const Char> vector = GetCharVector<Char>(string); if (is_ascii) { - SerializeStringUnchecked_( + current_index_ += SerializeStringUnchecked_( vector.start(), - SeqOneByteString::cast(*current_part_)->GetChars(), + SeqOneByteString::cast(*current_part_)->GetChars() + current_index_, length); } else { - SerializeStringUnchecked_( + current_index_ += SerializeStringUnchecked_( vector.start(), - SeqTwoByteString::cast(*current_part_)->GetChars(), + SeqTwoByteString::cast(*current_part_)->GetChars() + current_index_, length); } } else { diff --git a/deps/v8/src/log.cc b/deps/v8/src/log.cc index e9ef38215..94385373c 100644 --- a/deps/v8/src/log.cc +++ b/deps/v8/src/log.cc @@ -644,7 +644,17 @@ void Logger::ApiNamedSecurityCheck(Object* key) { String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); ApiEvent("api,check-security,\"%s\"\n", *str); } else if (key->IsSymbol()) { - ApiEvent("api,check-security,symbol(hash %x)\n", Symbol::cast(key)->Hash()); + Symbol* symbol = Symbol::cast(key); + if (symbol->name()->IsUndefined()) { + ApiEvent("api,check-security,symbol(hash %x)\n", + Symbol::cast(key)->Hash()); + } else { + SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString( + DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); + ApiEvent("api,check-security,symbol(\"%s\" hash %x)\n", + *str, + Symbol::cast(key)->Hash()); + } } else if (key->IsUndefined()) { ApiEvent("api,check-security,undefined\n"); } else { @@ -833,8 +843,16 @@ void Logger::ApiNamedPropertyAccess(const char* tag, String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, *class_name, *property_name); } else { - uint32_t hash = Symbol::cast(name)->Hash(); - ApiEvent("api,%s,\"%s\",symbol(hash %x)\n", tag, *class_name, hash); + Symbol* symbol = Symbol::cast(name); + uint32_t hash = symbol->Hash(); + if (symbol->name()->IsUndefined()) { + ApiEvent("api,%s,\"%s\",symbol(hash %x)\n", tag, *class_name, hash); + } else { + SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString( + DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); + ApiEvent("api,%s,\"%s\",symbol(\"%s\" hash %x)\n", + tag, *class_name, *str, hash); + } } } @@ -902,7 +920,14 @@ void Logger::CallbackEventInternal(const char* prefix, Name* name, String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); msg.Append(",1,\"%s%s\"", prefix, *str); } else { - msg.Append(",1,symbol(hash %x)", prefix, Name::cast(name)->Hash()); + Symbol* symbol = Symbol::cast(name); + if (symbol->name()->IsUndefined()) { + msg.Append(",1,symbol(hash %x)", prefix, symbol->Hash()); + } else { + SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString( + DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); + msg.Append(",1,symbol(\"%s\" hash %x)", prefix, *str, symbol->Hash()); + } } msg.Append('\n'); msg.WriteToLogFile(); @@ -978,8 +1003,15 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, if (name->IsString()) { name_buffer_->AppendString(String::cast(name)); } else { - name_buffer_->AppendBytes("symbol(hash "); - name_buffer_->AppendHex(Name::cast(name)->Hash()); + Symbol* symbol = Symbol::cast(name); + name_buffer_->AppendBytes("symbol("); + if (!symbol->name()->IsUndefined()) { + name_buffer_->AppendBytes("\""); + name_buffer_->AppendString(String::cast(symbol->name())); + name_buffer_->AppendBytes("\" "); + } + name_buffer_->AppendBytes("hash "); + name_buffer_->AppendHex(symbol->Hash()); name_buffer_->AppendByte(')'); } } @@ -1006,7 +1038,14 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, msg.AppendDetailed(String::cast(name), false); msg.Append('"'); } else { - msg.Append("symbol(hash %x)", Name::cast(name)->Hash()); + Symbol* symbol = Symbol::cast(name); + msg.Append("symbol("); + if (!symbol->name()->IsUndefined()) { + msg.Append("\""); + msg.AppendDetailed(String::cast(symbol->name()), false); + msg.Append("\" "); + } + msg.Append("hash %x)", symbol->Hash()); } msg.Append('\n'); msg.WriteToLogFile(); @@ -1036,8 +1075,15 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, if (name->IsString()) { name_buffer_->AppendString(String::cast(name)); } else { - name_buffer_->AppendBytes("symbol(hash "); - name_buffer_->AppendHex(Name::cast(name)->Hash()); + Symbol* symbol = Symbol::cast(name); + name_buffer_->AppendBytes("symbol("); + if (!symbol->name()->IsUndefined()) { + name_buffer_->AppendBytes("\""); + name_buffer_->AppendString(String::cast(symbol->name())); + name_buffer_->AppendBytes("\" "); + } + name_buffer_->AppendBytes("hash "); + name_buffer_->AppendHex(symbol->Hash()); name_buffer_->AppendByte(')'); } } @@ -1073,7 +1119,14 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); msg.Append("\"%s\"", *str); } else { - msg.Append("symbol(hash %x)", Name::cast(name)->Hash()); + Symbol* symbol = Symbol::cast(name); + msg.Append("symbol("); + if (!symbol->name()->IsUndefined()) { + msg.Append("\""); + msg.AppendDetailed(String::cast(symbol->name()), false); + msg.Append("\" "); + } + msg.Append("hash %x)", symbol->Hash()); } msg.Append(','); msg.AppendAddress(shared->address()); @@ -1138,7 +1191,14 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, String::cast(source)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); msg.Append("%s", *sourcestr); } else { - msg.Append("symbol(hash %x)", Name::cast(source)->Hash()); + Symbol* symbol = Symbol::cast(source); + msg.Append("symbol("); + if (!symbol->name()->IsUndefined()) { + msg.Append("\""); + msg.AppendDetailed(String::cast(symbol->name()), false); + msg.Append("\" "); + } + msg.Append("hash %x)", symbol->Hash()); } msg.Append(":%d\",", line); msg.AppendAddress(shared->address()); @@ -1358,7 +1418,14 @@ void Logger::SuspectReadEvent(Name* name, Object* obj) { msg.Append(String::cast(name)); msg.Append('"'); } else { - msg.Append("symbol(hash %x)", Name::cast(name)->Hash()); + Symbol* symbol = Symbol::cast(name); + msg.Append("symbol("); + if (!symbol->name()->IsUndefined()) { + msg.Append("\""); + msg.AppendDetailed(String::cast(symbol->name()), false); + msg.Append("\" "); + } + msg.Append("hash %x)", symbol->Hash()); } msg.Append('\n'); msg.WriteToLogFile(); diff --git a/deps/v8/src/log.h b/deps/v8/src/log.h index 5c121bc31..a5eddc7a3 100644 --- a/deps/v8/src/log.h +++ b/deps/v8/src/log.h @@ -77,6 +77,7 @@ class Semaphore; class Ticker; class Isolate; class PositionsRecorder; +class CpuProfiler; #undef LOG #define LOG(isolate, Call) \ diff --git a/deps/v8/src/macros.py b/deps/v8/src/macros.py index 291a898f5..92ed437b0 100644 --- a/deps/v8/src/macros.py +++ b/deps/v8/src/macros.py @@ -99,7 +99,7 @@ macro IS_UNDEFINED(arg) = (typeof(arg) === 'undefined'); macro IS_NUMBER(arg) = (typeof(arg) === 'number'); macro IS_STRING(arg) = (typeof(arg) === 'string'); macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean'); -macro IS_SYMBOL(arg) = (%_IsSymbol(arg)); +macro IS_SYMBOL(arg) = (typeof(arg) === 'symbol'); macro IS_OBJECT(arg) = (%_IsObject(arg)); macro IS_ARRAY(arg) = (%_IsArray(arg)); macro IS_FUNCTION(arg) = (%_IsFunction(arg)); @@ -110,11 +110,13 @@ macro IS_WEAKMAP(arg) = (%_ClassOf(arg) === 'WeakMap'); macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date'); macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number'); macro IS_STRING_WRAPPER(arg) = (%_ClassOf(arg) === 'String'); +macro IS_SYMBOL_WRAPPER(arg) = (%_ClassOf(arg) === 'Symbol'); macro IS_BOOLEAN_WRAPPER(arg) = (%_ClassOf(arg) === 'Boolean'); macro IS_ERROR(arg) = (%_ClassOf(arg) === 'Error'); macro IS_SCRIPT(arg) = (%_ClassOf(arg) === 'Script'); macro IS_ARGUMENTS(arg) = (%_ClassOf(arg) === 'Arguments'); macro IS_GLOBAL(arg) = (%_ClassOf(arg) === 'global'); +macro IS_ARRAYBUFFER(arg) = (%_ClassOf(arg) === '__ArrayBuffer'); macro IS_UNDETECTABLE(arg) = (%_IsUndetectableObject(arg)); macro FLOOR(arg) = $floor(arg); @@ -141,6 +143,7 @@ const kBoundArgumentsStartIndex = 2; macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg)); macro NUMBER_IS_FINITE(arg) = (%_IsSmi(%IS_VAR(arg)) || ((arg == arg) && (arg != 1/0) && (arg != -1/0))); macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToInteger(ToNumber(arg))); +macro TO_POSITIVE_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? (arg > 0 ? arg : 0) : %NumberToPositiveInteger(ToNumber(arg))); macro TO_INTEGER_MAP_MINUS_ZERO(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToIntegerMapMinusZero(ToNumber(arg))); macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0)); macro TO_UINT32(arg) = (arg >>> 0); diff --git a/deps/v8/src/messages.js b/deps/v8/src/messages.js index 7353444b4..d51d38475 100644 --- a/deps/v8/src/messages.js +++ b/deps/v8/src/messages.js @@ -100,6 +100,7 @@ var kMessages = { observe_notify_non_notifier: ["notify called on non-notifier object"], // RangeError invalid_array_length: ["Invalid array length"], + invalid_array_buffer_length: ["Invalid array buffer length"], stack_overflow: ["Maximum call stack size exceeded"], invalid_time_value: ["Invalid time value"], // SyntaxError @@ -150,6 +151,7 @@ var kMessages = { cant_prevent_ext_external_array_elements: ["Cannot prevent extension of an object with external array elements"], redef_external_array_element: ["Cannot redefine a property of an object with external array elements"], harmony_const_assign: ["Assignment to constant variable."], + symbol_to_string: ["Conversion from symbol to string"], invalid_module_path: ["Module does not export '", "%0", "', or export is not itself a module"], module_type_error: ["Module '", "%0", "' used improperly"], module_export_undefined: ["Export '", "%0", "' is not defined in module"], @@ -745,64 +747,70 @@ function GetPositionInLine(message) { function GetStackTraceLine(recv, fun, pos, isGlobal) { - return new CallSite(recv, fun, pos).toString(); + return new CallSite(recv, fun, pos, false).toString(); } // ---------------------------------------------------------------------------- // Error implementation -function CallSite(receiver, fun, pos) { - this.receiver = receiver; - this.fun = fun; - this.pos = pos; +var CallSiteReceiverKey = %CreateSymbol("receiver"); +var CallSiteFunctionKey = %CreateSymbol("function"); +var CallSitePositionKey = %CreateSymbol("position"); +var CallSiteStrictModeKey = %CreateSymbol("strict mode"); + +function CallSite(receiver, fun, pos, strict_mode) { + this[CallSiteReceiverKey] = receiver; + this[CallSiteFunctionKey] = fun; + this[CallSitePositionKey] = pos; + this[CallSiteStrictModeKey] = strict_mode; } function CallSiteGetThis() { - return this.receiver; + return this[CallSiteStrictModeKey] ? void 0 : this[CallSiteReceiverKey]; } function CallSiteGetTypeName() { - return GetTypeName(this, false); + return GetTypeName(this[CallSiteReceiverKey], false); } function CallSiteIsToplevel() { - if (this.receiver == null) { + if (this[CallSiteReceiverKey] == null) { return true; } - return IS_GLOBAL(this.receiver); + return IS_GLOBAL(this[CallSiteReceiverKey]); } function CallSiteIsEval() { - var script = %FunctionGetScript(this.fun); + var script = %FunctionGetScript(this[CallSiteFunctionKey]); return script && script.compilation_type == COMPILATION_TYPE_EVAL; } function CallSiteGetEvalOrigin() { - var script = %FunctionGetScript(this.fun); + var script = %FunctionGetScript(this[CallSiteFunctionKey]); return FormatEvalOrigin(script); } function CallSiteGetScriptNameOrSourceURL() { - var script = %FunctionGetScript(this.fun); + var script = %FunctionGetScript(this[CallSiteFunctionKey]); return script ? script.nameOrSourceURL() : null; } function CallSiteGetFunction() { - return this.fun; + return this[CallSiteStrictModeKey] ? void 0 : this[CallSiteFunctionKey]; } function CallSiteGetFunctionName() { // See if the function knows its own name - var name = this.fun.name; + var name = this[CallSiteFunctionKey].name; if (name) { return name; } - name = %FunctionGetInferredName(this.fun); + name = %FunctionGetInferredName(this[CallSiteFunctionKey]); if (name) { return name; } // Maybe this is an evaluation? - var script = %FunctionGetScript(this.fun); + var script = %FunctionGetScript(this[CallSiteFunctionKey]); if (script && script.compilation_type == COMPILATION_TYPE_EVAL) { return "eval"; } @@ -812,26 +820,22 @@ function CallSiteGetFunctionName() { function CallSiteGetMethodName() { // See if we can find a unique property on the receiver that holds // this function. - var ownName = this.fun.name; - if (ownName && this.receiver && - (%_CallFunction(this.receiver, - ownName, - ObjectLookupGetter) === this.fun || - %_CallFunction(this.receiver, - ownName, - ObjectLookupSetter) === this.fun || - (IS_OBJECT(this.receiver) && - %GetDataProperty(this.receiver, ownName) === this.fun))) { + var receiver = this[CallSiteReceiverKey]; + var fun = this[CallSiteFunctionKey]; + var ownName = fun.name; + if (ownName && receiver && + (%_CallFunction(receiver, ownName, ObjectLookupGetter) === fun || + %_CallFunction(receiver, ownName, ObjectLookupSetter) === fun || + (IS_OBJECT(receiver) && %GetDataProperty(receiver, ownName) === fun))) { // To handle DontEnum properties we guess that the method has // the same name as the function. return ownName; } var name = null; - for (var prop in this.receiver) { - if (%_CallFunction(this.receiver, prop, ObjectLookupGetter) === this.fun || - %_CallFunction(this.receiver, prop, ObjectLookupSetter) === this.fun || - (IS_OBJECT(this.receiver) && - %GetDataProperty(this.receiver, prop) === this.fun)) { + for (var prop in receiver) { + if (%_CallFunction(receiver, prop, ObjectLookupGetter) === fun || + %_CallFunction(receiver, prop, ObjectLookupSetter) === fun || + (IS_OBJECT(receiver) && %GetDataProperty(receiver, prop) === fun)) { // If we find more than one match bail out to avoid confusion. if (name) { return null; @@ -846,49 +850,49 @@ function CallSiteGetMethodName() { } function CallSiteGetFileName() { - var script = %FunctionGetScript(this.fun); + var script = %FunctionGetScript(this[CallSiteFunctionKey]); return script ? script.name : null; } function CallSiteGetLineNumber() { - if (this.pos == -1) { + if (this[CallSitePositionKey] == -1) { return null; } - var script = %FunctionGetScript(this.fun); + var script = %FunctionGetScript(this[CallSiteFunctionKey]); var location = null; if (script) { - location = script.locationFromPosition(this.pos, true); + location = script.locationFromPosition(this[CallSitePositionKey], true); } return location ? location.line + 1 : null; } function CallSiteGetColumnNumber() { - if (this.pos == -1) { + if (this[CallSitePositionKey] == -1) { return null; } - var script = %FunctionGetScript(this.fun); + var script = %FunctionGetScript(this[CallSiteFunctionKey]); var location = null; if (script) { - location = script.locationFromPosition(this.pos, true); + location = script.locationFromPosition(this[CallSitePositionKey], true); } return location ? location.column + 1: null; } function CallSiteIsNative() { - var script = %FunctionGetScript(this.fun); + var script = %FunctionGetScript(this[CallSiteFunctionKey]); return script ? (script.type == TYPE_NATIVE) : false; } function CallSiteGetPosition() { - return this.pos; + return this[CallSitePositionKey]; } function CallSiteIsConstructor() { - var receiver = this.receiver; + var receiver = this[CallSiteReceiverKey]; var constructor = IS_OBJECT(receiver) ? %GetDataProperty(receiver, "constructor") : null; if (!constructor) return false; - return this.fun === constructor; + return this[CallSiteFunctionKey] === constructor; } function CallSiteToString() { @@ -931,7 +935,7 @@ function CallSiteToString() { var isConstructor = this.isConstructor(); var isMethodCall = !(this.isToplevel() || isConstructor); if (isMethodCall) { - var typeName = GetTypeName(this, true); + var typeName = GetTypeName(this[CallSiteReceiverKey], true); var methodName = this.getMethodName(); if (functionName) { if (typeName && @@ -1035,13 +1039,15 @@ function FormatErrorString(error) { function GetStackFrames(raw_stack) { var frames = new InternalArray(); - for (var i = 0; i < raw_stack.length; i += 4) { + var non_strict_frames = raw_stack[0]; + for (var i = 1; i < raw_stack.length; i += 4) { var recv = raw_stack[i]; var fun = raw_stack[i + 1]; var code = raw_stack[i + 2]; var pc = raw_stack[i + 3]; var pos = %FunctionGetPositionForOffset(code, pc); - frames.push(new CallSite(recv, fun, pos)); + non_strict_frames--; + frames.push(new CallSite(recv, fun, pos, (non_strict_frames < 0))); } return frames; } @@ -1069,16 +1075,16 @@ function FormatStackTrace(error_string, frames) { } -function GetTypeName(obj, requireConstructor) { - var constructor = obj.receiver.constructor; +function GetTypeName(receiver, requireConstructor) { + var constructor = receiver.constructor; if (!constructor) { return requireConstructor ? null : - %_CallFunction(obj.receiver, ObjectToString); + %_CallFunction(receiver, ObjectToString); } var constructorName = constructor.name; if (!constructorName) { return requireConstructor ? null : - %_CallFunction(obj.receiver, ObjectToString); + %_CallFunction(receiver, ObjectToString); } return constructorName; } diff --git a/deps/v8/src/mips/OWNERS b/deps/v8/src/mips/OWNERS new file mode 100644 index 000000000..3cb222c46 --- /dev/null +++ b/deps/v8/src/mips/OWNERS @@ -0,0 +1 @@ +plind44@gmail.com diff --git a/deps/v8/src/mips/assembler-mips.cc b/deps/v8/src/mips/assembler-mips.cc index 4c11c7f54..c255d0fbd 100644 --- a/deps/v8/src/mips/assembler-mips.cc +++ b/deps/v8/src/mips/assembler-mips.cc @@ -490,7 +490,6 @@ bool Assembler::IsBranch(Instr instr) { uint32_t opcode = GetOpcodeField(instr); uint32_t rt_field = GetRtField(instr); uint32_t rs_field = GetRsField(instr); - uint32_t label_constant = GetLabelConst(instr); // Checks if the instruction is a branch. return opcode == BEQ || opcode == BNE || @@ -502,10 +501,13 @@ bool Assembler::IsBranch(Instr instr) { opcode == BGTZL || (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ || rt_field == BLTZAL || rt_field == BGEZAL)) || - (opcode == COP1 && rs_field == BC1) || // Coprocessor branch. - label_constant == 0; // Emitted label const in reg-exp engine. + (opcode == COP1 && rs_field == BC1); // Coprocessor branch. } +bool Assembler::IsEmittedConstant(Instr instr) { + uint32_t label_constant = GetLabelConst(instr); + return label_constant == 0; // Emitted label const in reg-exp engine. +} bool Assembler::IsBeq(Instr instr) { return GetOpcodeField(instr) == BEQ; @@ -796,7 +798,7 @@ void Assembler::bind_to(Label* L, int pos) { } target_at_put(fixup_pos, pos); } else { - ASSERT(IsJ(instr) || IsLui(instr)); + ASSERT(IsJ(instr) || IsLui(instr) || IsEmittedConstant(instr)); target_at_put(fixup_pos, pos); } } diff --git a/deps/v8/src/mips/assembler-mips.h b/deps/v8/src/mips/assembler-mips.h index e6c9e76c7..9d3d39b83 100644 --- a/deps/v8/src/mips/assembler-mips.h +++ b/deps/v8/src/mips/assembler-mips.h @@ -942,6 +942,7 @@ class Assembler : public AssemblerBase { static Instr SetAddImmediateOffset(Instr instr, int16_t offset); static bool IsAndImmediate(Instr instr); + static bool IsEmittedConstant(Instr instr); void CheckTrampolinePool(); diff --git a/deps/v8/src/mips/builtins-mips.cc b/deps/v8/src/mips/builtins-mips.cc index 54efd9491..1901f9c41 100644 --- a/deps/v8/src/mips/builtins-mips.cc +++ b/deps/v8/src/mips/builtins-mips.cc @@ -227,13 +227,12 @@ static void AllocateJSArray(MacroAssembler* masm, (JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize); __ sra(scratch1, array_size, kSmiTagSize); __ Addu(elements_array_end, elements_array_end, scratch1); - __ AllocateInNewSpace( - elements_array_end, - result, - scratch1, - scratch2, - gc_required, - static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS)); + __ Allocate(elements_array_end, + result, + scratch1, + scratch2, + gc_required, + static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS)); // Allocated the JSArray. Now initialize the fields except for the elements // array. @@ -895,7 +894,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // a1: constructor function // a2: initial map __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset)); - __ AllocateInNewSpace(a3, t4, t5, t6, &rt_call, SIZE_IN_WORDS); + __ Allocate(a3, t4, t5, t6, &rt_call, SIZE_IN_WORDS); // Allocated the JSObject, now initialize the fields. Map is set to // initial map and properties and elements are set to empty fixed array. @@ -974,7 +973,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // t4: JSObject // t5: start of next object __ Addu(a0, a3, Operand(FixedArray::kHeaderSize / kPointerSize)); - __ AllocateInNewSpace( + __ Allocate( a0, t5, t6, @@ -1130,10 +1129,6 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, __ GetObjectType(v0, a1, a3); __ Branch(&exit, greater_equal, a3, Operand(FIRST_SPEC_OBJECT_TYPE)); - // Symbols are "objects". - __ lbu(a3, FieldMemOperand(a1, Map::kInstanceTypeOffset)); - __ Branch(&exit, eq, a3, Operand(SYMBOL_TYPE)); - // Throw away the result of the constructor invocation and use the // on-stack receiver as the result. __ bind(&use_receiver); diff --git a/deps/v8/src/mips/code-stubs-mips.cc b/deps/v8/src/mips/code-stubs-mips.cc index f5908d37b..37d7720c8 100644 --- a/deps/v8/src/mips/code-stubs-mips.cc +++ b/deps/v8/src/mips/code-stubs-mips.cc @@ -62,6 +62,17 @@ void KeyedLoadFastElementStub::InitializeInterfaceDescriptor( } +void KeyedStoreFastElementStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + static Register registers[] = { a2, a1, a0 }; + descriptor->register_param_count_ = 3; + descriptor->register_params_ = registers; + descriptor->deoptimization_handler_ = + FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure); +} + + void TransitionElementsKindStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { @@ -85,7 +96,7 @@ static void InitializeArrayConstructorDescriptor(Isolate* isolate, // stack param count needs (constructor pointer, and single argument) descriptor->stack_parameter_count_ = &a0; descriptor->register_params_ = registers; - descriptor->extra_expression_stack_count_ = 1; + descriptor->function_mode_ = JS_FUNCTION_STUB_MODE; descriptor->deoptimization_handler_ = FUNCTION_ADDR(ArrayConstructor_StubFailure); } @@ -673,6 +684,8 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm, Register scratch1, Register scratch2, Label* not_number) { + ASSERT(!object.is(dst1) && !object.is(dst2)); + __ AssertRootValue(heap_number_map, Heap::kHeapNumberMapRootIndex, "HeapNumberMap register clobbered."); @@ -867,6 +880,10 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm, ASSERT(!heap_number_map.is(object) && !heap_number_map.is(scratch1) && !heap_number_map.is(scratch2)); + // ARM uses pop/push and Ldlr to save dst_* and probably object registers in + // softfloat path. On MIPS there is no ldlr, 1st lw instruction may overwrite + // object register making the 2nd lw invalid. + ASSERT(!object.is(dst_mantissa) && !object.is(dst_exponent)); Label done, obj_is_not_smi; @@ -903,49 +920,24 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm, if (destination == kCoreRegisters) { __ Move(dst_mantissa, dst_exponent, double_dst); } - } else { - ASSERT(!scratch1.is(object) && !scratch2.is(object)); // Load the double value in the destination registers. - bool save_registers = object.is(dst_mantissa) || object.is(dst_exponent); - if (save_registers) { - // Save both output registers, because the other one probably holds - // an important value too. - __ Push(dst_exponent, dst_mantissa); - } __ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset)); __ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset)); // Check for 0 and -0. - Label zero; __ And(scratch1, dst_exponent, Operand(~HeapNumber::kSignMask)); __ Or(scratch1, scratch1, Operand(dst_mantissa)); - __ Branch(&zero, eq, scratch1, Operand(zero_reg)); + __ Branch(&done, eq, scratch1, Operand(zero_reg)); // Check that the value can be exactly represented by a 32-bit integer. // Jump to not_int32 if that's not the case. - Label restore_input_and_miss; DoubleIs32BitInteger(masm, dst_exponent, dst_mantissa, scratch1, scratch2, - &restore_input_and_miss); + not_int32); // dst_* were trashed. Reload the double value. - if (save_registers) { - __ Pop(dst_exponent, dst_mantissa); - } __ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset)); __ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset)); - __ Branch(&done); - - __ bind(&restore_input_and_miss); - if (save_registers) { - __ Pop(dst_exponent, dst_mantissa); - } - __ Branch(not_int32); - - __ bind(&zero); - if (save_registers) { - __ Drop(2); - } } __ bind(&done); @@ -2696,16 +2688,20 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm, masm, destination, right, f14, a2, a3, heap_number_map, scratch1, scratch2, fail); } + // Use scratch3 as left in LoadNumber functions to avoid overwriting of + // left (a0) register. + __ mov(scratch3, left); + // Load left operand to f12 or a0/a1. This keeps a0/a1 intact if it // jumps to |miss|. if (left_type == BinaryOpIC::INT32) { FloatingPointHelper::LoadNumberAsInt32Double( - masm, left, destination, f12, f16, a0, a1, heap_number_map, + masm, scratch3, destination, f12, f16, a0, a1, heap_number_map, scratch1, scratch2, f2, miss); } else { Label* fail = (left_type == BinaryOpIC::NUMBER) ? miss : not_numbers; FloatingPointHelper::LoadNumber( - masm, destination, left, f12, a0, a1, heap_number_map, + masm, destination, scratch3, f12, a0, a1, heap_number_map, scratch1, scratch2, fail); } } @@ -4544,35 +4540,6 @@ void InstanceofStub::Generate(MacroAssembler* masm) { } -void ArrayLengthStub::Generate(MacroAssembler* masm) { - Label miss; - Register receiver; - if (kind() == Code::KEYED_LOAD_IC) { - // ----------- S t a t e ------------- - // -- ra : return address - // -- a0 : key - // -- a1 : receiver - // ----------------------------------- - __ Branch(&miss, ne, a0, - Operand(masm->isolate()->factory()->length_string())); - receiver = a1; - } else { - ASSERT(kind() == Code::LOAD_IC); - // ----------- S t a t e ------------- - // -- a2 : name - // -- ra : return address - // -- a0 : receiver - // -- sp[0] : receiver - // ----------------------------------- - receiver = a0; - } - - StubCompiler::GenerateLoadArrayLength(masm, receiver, a3, &miss); - __ bind(&miss); - StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind())); -} - - void FunctionPrototypeStub::Generate(MacroAssembler* masm) { Label miss; Register receiver; @@ -4861,7 +4828,7 @@ void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { __ Addu(t5, t5, Operand(Heap::kArgumentsObjectSize)); // Do the allocation of all three objects in one go. - __ AllocateInNewSpace(t5, v0, a3, t0, &runtime, TAG_OBJECT); + __ Allocate(t5, v0, a3, t0, &runtime, TAG_OBJECT); // v0 = address of new object(s) (tagged) // a2 = argument count (tagged) @@ -5052,13 +5019,8 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { __ Addu(a1, a1, Operand(Heap::kArgumentsObjectSizeStrict / kPointerSize)); // Do the allocation of both objects in one go. - __ AllocateInNewSpace(a1, - v0, - a2, - a3, - &runtime, - static_cast<AllocationFlags>(TAG_OBJECT | - SIZE_IN_WORDS)); + __ Allocate(a1, v0, a2, a3, &runtime, + static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS)); // Get the arguments boilerplate from the current native context. __ lw(t0, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); @@ -5578,7 +5540,7 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) { (JSRegExpResult::kSize + FixedArray::kHeaderSize) / kPointerSize; __ srl(t1, a1, kSmiTagSize + kSmiShiftSize); __ Addu(a2, t1, Operand(objects_size)); - __ AllocateInNewSpace( + __ Allocate( a2, // In: Size, in words. v0, // Out: Start of allocation (tagged). a3, // Scratch register. @@ -7543,30 +7505,28 @@ void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm, __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex); __ Branch(done, eq, entity_name, Operand(tmp)); - if (i != kInlinedProbes - 1) { - // Load the hole ready for use below: - __ LoadRoot(tmp, Heap::kTheHoleValueRootIndex); + // Load the hole ready for use below: + __ LoadRoot(tmp, Heap::kTheHoleValueRootIndex); + + // Stop if found the property. + __ Branch(miss, eq, entity_name, Operand(Handle<Name>(name))); - // Stop if found the property. - __ Branch(miss, eq, entity_name, Operand(Handle<Name>(name))); + Label good; + __ Branch(&good, eq, entity_name, Operand(tmp)); - Label good; - __ Branch(&good, eq, entity_name, Operand(tmp)); + // Check if the entry name is not a unique name. + __ lw(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); + __ lbu(entity_name, + FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); + __ And(scratch0, entity_name, Operand(kIsInternalizedMask)); + __ Branch(&good, ne, scratch0, Operand(zero_reg)); + __ Branch(miss, ne, entity_name, Operand(SYMBOL_TYPE)); - // Check if the entry name is not a unique name. - __ lw(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); - __ lbu(entity_name, - FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); - __ And(scratch0, entity_name, Operand(kIsInternalizedMask)); - __ Branch(&good, ne, scratch0, Operand(zero_reg)); - __ Branch(miss, ne, entity_name, Operand(SYMBOL_TYPE)); - - __ bind(&good); - - // Restore the properties. - __ lw(properties, - FieldMemOperand(receiver, JSObject::kPropertiesOffset)); - } + __ bind(&good); + + // Restore the properties. + __ lw(properties, + FieldMemOperand(receiver, JSObject::kPropertiesOffset)); } const int spill_mask = @@ -8127,6 +8087,9 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) { int parameter_count_offset = StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset; __ lw(a1, MemOperand(fp, parameter_count_offset)); + if (function_mode_ == JS_FUNCTION_STUB_MODE) { + __ Addu(a1, a1, Operand(1)); + } masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE); __ sll(a1, a1, kPointerSizeLog2); __ Addu(sp, sp, a1); diff --git a/deps/v8/src/mips/codegen-mips.cc b/deps/v8/src/mips/codegen-mips.cc index f5cb5e489..bd403cee6 100644 --- a/deps/v8/src/mips/codegen-mips.cc +++ b/deps/v8/src/mips/codegen-mips.cc @@ -206,8 +206,9 @@ void ElementsTransitionGenerator::GenerateSmiToDouble( // Allocate new FixedDoubleArray. __ sll(scratch, t1, 2); __ Addu(scratch, scratch, FixedDoubleArray::kHeaderSize); - __ AllocateInNewSpace(scratch, t2, t3, t5, &gc_required, NO_ALLOCATION_FLAGS); + __ 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. __ LoadRoot(t5, Heap::kFixedDoubleArrayMapRootIndex); __ sw(t1, MemOperand(t2, FixedDoubleArray::kLengthOffset)); @@ -351,7 +352,7 @@ void ElementsTransitionGenerator::GenerateDoubleToObject( // Allocate new FixedArray. __ sll(a0, t1, 1); __ Addu(a0, a0, FixedDoubleArray::kHeaderSize); - __ AllocateInNewSpace(a0, t2, t3, t5, &gc_required, NO_ALLOCATION_FLAGS); + __ Allocate(a0, t2, t3, t5, &gc_required, NO_ALLOCATION_FLAGS); // t2: destination FixedArray, not tagged as heap object // Set destination FixedDoubleArray's length and map. __ LoadRoot(t5, Heap::kFixedArrayMapRootIndex); @@ -702,7 +703,7 @@ void Code::PatchPlatformCodeAge(byte* sequence, uint32_t young_length; byte* young_sequence = GetNoCodeAgeSequence(&young_length); if (age == kNoAge) { - memcpy(sequence, young_sequence, young_length); + CopyBytes(sequence, young_sequence, young_length); CPU::FlushICache(sequence, young_length); } else { Code* stub = GetCodeAgeStub(age, parity); diff --git a/deps/v8/src/mips/full-codegen-mips.cc b/deps/v8/src/mips/full-codegen-mips.cc index bacec10f0..3e7c8da7a 100644 --- a/deps/v8/src/mips/full-codegen-mips.cc +++ b/deps/v8/src/mips/full-codegen-mips.cc @@ -2780,28 +2780,6 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( } -void FullCodeGenerator::EmitIsSymbol(CallRuntime* expr) { - ZoneList<Expression*>* args = expr->arguments(); - ASSERT(args->length() == 1); - - VisitForAccumulatorValue(args->at(0)); - - Label materialize_true, materialize_false; - Label* if_true = NULL; - Label* if_false = NULL; - Label* fall_through = NULL; - context()->PrepareTest(&materialize_true, &materialize_false, - &if_true, &if_false, &fall_through); - - __ JumpIfSmi(v0, if_false); - __ GetObjectType(v0, a1, a2); - PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - Split(eq, a2, Operand(SYMBOL_TYPE), if_true, if_false, fall_through); - - context()->Plug(if_true, if_false); -} - - void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) { ZoneList<Expression*>* args = expr->arguments(); ASSERT(args->length() == 1); @@ -4320,6 +4298,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ And(a1, a1, Operand(1 << Map::kIsUndetectable)); Split(eq, a1, Operand(zero_reg), if_true, if_false, fall_through); + } else if (check->Equals(isolate()->heap()->symbol_string())) { + __ JumpIfSmi(v0, if_false); + __ GetObjectType(v0, v0, a1); + Split(eq, a1, Operand(SYMBOL_TYPE), if_true, if_false, fall_through); } else if (check->Equals(isolate()->heap()->boolean_string())) { __ LoadRoot(at, Heap::kTrueValueRootIndex); __ Branch(if_true, eq, v0, Operand(at)); @@ -4351,10 +4333,6 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ LoadRoot(at, Heap::kNullValueRootIndex); __ Branch(if_true, eq, v0, Operand(at)); } - if (FLAG_harmony_symbols) { - __ GetObjectType(v0, v0, a1); - __ Branch(if_true, eq, a1, Operand(SYMBOL_TYPE)); - } // Check for JS objects => true. __ GetObjectType(v0, v0, a1); __ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); diff --git a/deps/v8/src/mips/lithium-codegen-mips.cc b/deps/v8/src/mips/lithium-codegen-mips.cc index cd489346a..b5d6c451f 100644 --- a/deps/v8/src/mips/lithium-codegen-mips.cc +++ b/deps/v8/src/mips/lithium-codegen-mips.cc @@ -237,7 +237,7 @@ bool LCodeGen::GeneratePrologue() { __ sw(a0, target); // Update the write barrier. This clobbers a3 and a0. __ RecordWriteContextSlot( - cp, target.offset(), a0, a3, kRAHasBeenSaved, kSaveFPRegs); + cp, target.offset(), a0, a3, GetRAState(), kSaveFPRegs); } } Comment(";;; End allocate local context"); @@ -1492,13 +1492,6 @@ void LCodeGen::DoConstantT(LConstantT* instr) { } -void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { - Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->value()); - __ lw(result, FieldMemOperand(array, JSArray::kLengthOffset)); -} - - void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) { Register result = ToRegister(instr->result()); Register array = ToRegister(instr->value()); @@ -1901,6 +1894,13 @@ void LCodeGen::DoBranch(LBranch* instr) { __ bind(¬_string); } + if (expected.Contains(ToBooleanStub::SYMBOL)) { + // Symbol value -> true. + const Register scratch = scratch1(); + __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); + __ Branch(true_label, eq, scratch, Operand(SYMBOL_TYPE)); + } + if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { CpuFeatureScope scope(masm(), FPU); // heap number -> false iff +0, -0, or NaN. @@ -2687,7 +2687,7 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { target.offset(), value, scratch0(), - kRAHasBeenSaved, + GetRAState(), kSaveFPRegs, EMIT_REMEMBERED_SET, check_needed); @@ -4030,7 +4030,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { HeapObject::kMapOffset, scratch, temp, - kRAHasBeenSaved, + GetRAState(), kSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); @@ -4049,7 +4049,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { offset, value, scratch, - kRAHasBeenSaved, + GetRAState(), kSaveFPRegs, EMIT_REMEMBERED_SET, check_needed); @@ -4064,7 +4064,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { offset, value, object, - kRAHasBeenSaved, + GetRAState(), kSaveFPRegs, EMIT_REMEMBERED_SET, check_needed); @@ -4275,7 +4275,7 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { __ RecordWrite(elements, key, value, - kRAHasBeenSaved, + GetRAState(), kSaveFPRegs, EMIT_REMEMBERED_SET, check_needed); @@ -4326,7 +4326,7 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { __ sw(new_map_reg, FieldMemOperand(object_reg, HeapObject::kMapOffset)); // Write barrier. __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, - scratch, kRAHasBeenSaved, kDontSaveFPRegs); + scratch, GetRAState(), kDontSaveFPRegs); } else if (FLAG_compiled_transitions) { PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); __ mov(a0, object_reg); @@ -4571,10 +4571,11 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) { // Convert unsigned integer with specified number of leading zeroes in binary // representation to IEEE 754 double. -// Integer to convert is passed in register hiword. +// Integer to convert is passed in register src. // Resulting double is returned in registers hiword:loword. // This functions does not work correctly for 0. static void GenerateUInt2Double(MacroAssembler* masm, + Register src, Register hiword, Register loword, Register scratch, @@ -4588,12 +4589,12 @@ static void GenerateUInt2Double(MacroAssembler* masm, kBitsPerInt - mantissa_shift_for_hi_word; masm->li(scratch, Operand(biased_exponent << HeapNumber::kExponentShift)); if (mantissa_shift_for_hi_word > 0) { - masm->sll(loword, hiword, mantissa_shift_for_lo_word); - masm->srl(hiword, hiword, mantissa_shift_for_hi_word); + masm->sll(loword, src, mantissa_shift_for_lo_word); + masm->srl(hiword, src, mantissa_shift_for_hi_word); masm->Or(hiword, scratch, hiword); } else { masm->mov(loword, zero_reg); - masm->sll(hiword, hiword, mantissa_shift_for_hi_word); + masm->sll(hiword, src, mantissa_shift_for_hi_word); masm->Or(hiword, scratch, hiword); } @@ -4644,17 +4645,17 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, __ mtc1(src, dbl_scratch); __ Cvt_d_uw(dbl_scratch, dbl_scratch, f22); } else { - Label no_leading_zero, done; + Label no_leading_zero, convert_done; __ And(at, src, Operand(0x80000000)); __ Branch(&no_leading_zero, ne, at, Operand(zero_reg)); // Integer has one leading zeros. - GenerateUInt2Double(masm(), sfpd_hi, sfpd_lo, t0, 1); - __ Branch(&done); + GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, t0, 1); + __ Branch(&convert_done); __ bind(&no_leading_zero); - GenerateUInt2Double(masm(), sfpd_hi, sfpd_lo, t0, 0); - __ Branch(&done); + GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, t0, 0); + __ bind(&convert_done); } } @@ -5344,12 +5345,12 @@ void LCodeGen::DoAllocate(LAllocate* instr) { __ Allocate(size, result, scratch, scratch2, deferred->entry(), flags); } else { Register size = ToRegister(instr->size()); - __ AllocateInNewSpace(size, - result, - scratch, - scratch2, - deferred->entry(), - flags); + __ Allocate(size, + result, + scratch, + scratch2, + deferred->entry(), + flags); } __ bind(deferred->exit()); @@ -5771,6 +5772,13 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, cmp2 = Operand(zero_reg); final_branch_condition = eq; + } else if (type_name->Equals(heap()->symbol_string())) { + __ JumpIfSmi(input, false_label); + __ GetObjectType(input, input, scratch); + cmp1 = scratch; + cmp2 = Operand(SYMBOL_TYPE); + final_branch_condition = eq; + } else if (type_name->Equals(heap()->boolean_string())) { __ LoadRoot(at, Heap::kTrueValueRootIndex); __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input)); @@ -5814,27 +5822,15 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, __ LoadRoot(at, Heap::kNullValueRootIndex); __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input)); } - if (FLAG_harmony_symbols) { - // input is an object, it is safe to use GetObjectType in the delay slot. - __ GetObjectType(input, input, scratch); - __ Branch(USE_DELAY_SLOT, true_label, eq, scratch, Operand(SYMBOL_TYPE)); - // Still an object, so the InstanceType can be loaded. - __ lbu(scratch, FieldMemOperand(input, Map::kInstanceTypeOffset)); - __ Branch(USE_DELAY_SLOT, false_label, - lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - } else { - // input is an object, it is safe to use GetObjectType in the delay slot. - __ GetObjectType(input, input, scratch); - __ Branch(USE_DELAY_SLOT, false_label, - lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); - } - // Still an object, so the InstanceType can be loaded. - __ lbu(scratch, FieldMemOperand(input, Map::kInstanceTypeOffset)); + Register map = input; + __ GetObjectType(input, map, scratch); + __ Branch(false_label, + lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); __ Branch(USE_DELAY_SLOT, false_label, gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); - // Still an object, so the BitField can be loaded. + // map is still valid, so the BitField can be loaded in delay slot. // Check for undetectable objects => false. - __ lbu(at, FieldMemOperand(input, Map::kBitFieldOffset)); + __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset)); __ And(at, at, 1 << Map::kIsUndetectable); cmp1 = at; cmp2 = Operand(zero_reg); diff --git a/deps/v8/src/mips/lithium-codegen-mips.h b/deps/v8/src/mips/lithium-codegen-mips.h index 1d2a65912..bb2003f1d 100644 --- a/deps/v8/src/mips/lithium-codegen-mips.h +++ b/deps/v8/src/mips/lithium-codegen-mips.h @@ -87,6 +87,10 @@ class LCodeGen BASE_EMBEDDED { return !NeedsEagerFrame() && info()->is_deferred_calling(); } + RAStatus GetRAState() const { + return frame_is_built_ ? kRAHasBeenSaved : kRAHasNotBeenSaved; + } + // Support for converting LOperands to assembler types. // LOperand must be a register. Register ToRegister(LOperand* op) const; diff --git a/deps/v8/src/mips/lithium-mips.cc b/deps/v8/src/mips/lithium-mips.cc index 8848032b6..652c7cad0 100644 --- a/deps/v8/src/mips/lithium-mips.cc +++ b/deps/v8/src/mips/lithium-mips.cc @@ -871,6 +871,35 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { LInstruction* instr = current->CompileToLithium(this); if (instr != NULL) { +#if DEBUG + // Make sure that the lithium instruction has either no fixed register + // constraints in temps or the result OR no uses that are only used at + // start. If this invariant doesn't hold, the register allocator can decide + // to insert a split of a range immediately before the instruction due to an + // already allocated register needing to be used for the instruction's fixed + // register constraint. In this case, The register allocator won't see an + // interference between the split child and the use-at-start (it would if + // the it was just a plain use), so it is free to move the split child into + // the same register that is used for the use-at-start. + // See https://code.google.com/p/chromium/issues/detail?id=201590 + if (!(instr->ClobbersRegisters() && instr->ClobbersDoubleRegisters())) { + int fixed = 0; + int used_at_start = 0; + for (UseIterator it(instr); !it.Done(); it.Advance()) { + LUnallocated* operand = LUnallocated::cast(it.Current()); + if (operand->IsUsedAtStart()) ++used_at_start; + } + if (instr->Output() != NULL) { + if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed; + } + for (TempIterator it(instr); !it.Done(); it.Advance()) { + LUnallocated* operand = LUnallocated::cast(it.Current()); + if (operand->HasFixedPolicy()) ++fixed; + } + ASSERT(fixed == 0 || used_at_start == 0); + } +#endif + if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) { instr = AssignPointerMap(instr); } @@ -1116,7 +1145,7 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp); return DefineFixedDouble(result, f4); } else { - LOperand* input = UseRegisterAtStart(instr->value()); + LOperand* input = UseRegister(instr->value()); LOperand* temp = (op == kMathRound) ? FixedTemp(f6) : (op == kMathFloor) ? TempRegister() : NULL; @@ -1585,12 +1614,6 @@ LInstruction* LChunkBuilder::DoClassOfTestAndBranch( } -LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) { - LOperand* array = UseRegisterAtStart(instr->value()); - return DefineAsRegister(new(zone()) LJSArrayLength(array)); -} - - LInstruction* LChunkBuilder::DoFixedArrayBaseLength( HFixedArrayBaseLength* instr) { LOperand* array = UseRegisterAtStart(instr->value()); @@ -1697,11 +1720,13 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { return AssignEnvironment(DefineAsRegister(res)); } else { ASSERT(to.IsInteger32()); - LOperand* value = UseRegisterAtStart(instr->value()); + LOperand* value = NULL; LInstruction* res = NULL; if (instr->value()->type().IsSmi()) { + value = UseRegisterAtStart(instr->value()); res = DefineAsRegister(new(zone()) LSmiUntag(value, false)); } else { + value = UseRegister(instr->value()); LOperand* temp1 = TempRegister(); LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister() : NULL; @@ -2081,7 +2106,7 @@ LInstruction* LChunkBuilder::DoTransitionElementsKind( LOperand* new_map_reg = TempRegister(); LTransitionElementsKind* result = new(zone()) LTransitionElementsKind(object, new_map_reg, NULL); - return DefineSameAsFirst(result); + return result; } else if (FLAG_compiled_transitions) { LTransitionElementsKind* result = new(zone()) LTransitionElementsKind(object, NULL, NULL); diff --git a/deps/v8/src/mips/lithium-mips.h b/deps/v8/src/mips/lithium-mips.h index 80635c389..e99590545 100644 --- a/deps/v8/src/mips/lithium-mips.h +++ b/deps/v8/src/mips/lithium-mips.h @@ -120,7 +120,6 @@ class LCodeGen; V(IsStringAndBranch) \ V(IsSmiAndBranch) \ V(IsUndetectableAndBranch) \ - V(JSArrayLength) \ V(Label) \ V(LazyBailout) \ V(LoadContextSlot) \ @@ -291,7 +290,6 @@ class LInstruction: public ZoneObject { SetOncePointer<LPointerMap> pointer_map_; HValue* hydrogen_value_; bool is_call_; - bool is_save_doubles_; }; @@ -1111,19 +1109,6 @@ class LCmpMapAndBranch: public LTemplateInstruction<0, 1, 1> { }; -class LJSArrayLength: public LTemplateInstruction<1, 1, 0> { - public: - explicit LJSArrayLength(LOperand* value) { - inputs_[0] = value; - } - - LOperand* value() { return inputs_[0]; } - - DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length") - DECLARE_HYDROGEN_ACCESSOR(JSArrayLength) -}; - - class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> { public: explicit LFixedArrayBaseLength(LOperand* value) { @@ -2060,7 +2045,7 @@ class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> { }; -class LTransitionElementsKind: public LTemplateInstruction<1, 1, 2> { +class LTransitionElementsKind: public LTemplateInstruction<0, 1, 2> { public: LTransitionElementsKind(LOperand* object, LOperand* new_map_temp, diff --git a/deps/v8/src/mips/macro-assembler-mips.cc b/deps/v8/src/mips/macro-assembler-mips.cc index 603f1be70..12e102504 100644 --- a/deps/v8/src/mips/macro-assembler-mips.cc +++ b/deps/v8/src/mips/macro-assembler-mips.cc @@ -1108,6 +1108,7 @@ void MacroAssembler::BranchF(Label* target, FPURegister cmp1, FPURegister cmp2, BranchDelaySlot bd) { + BlockTrampolinePoolScope block_trampoline_pool(this); if (cc == al) { Branch(bd, target); return; @@ -1700,6 +1701,7 @@ void MacroAssembler::BranchShort(int16_t offset, Condition cond, Register rs, if (rt.is_reg()) { // NOTE: 'at' can be clobbered by Branch but it is legal to use it as rs or // rt. + BlockTrampolinePoolScope block_trampoline_pool(this); r2 = rt.rm_; switch (cond) { case cc_always: @@ -1785,6 +1787,7 @@ void MacroAssembler::BranchShort(int16_t offset, Condition cond, Register rs, // Be careful to always use shifted_branch_offset only just before the // branch instruction, as the location will be remember for patching the // target. + BlockTrampolinePoolScope block_trampoline_pool(this); switch (cond) { case cc_always: b(offset); @@ -1925,10 +1928,11 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs, BranchDelaySlot bdslot) { BRANCH_ARGS_CHECK(cond, rs, rt); - int32_t offset; + int32_t offset = 0; Register r2 = no_reg; Register scratch = at; if (rt.is_reg()) { + BlockTrampolinePoolScope block_trampoline_pool(this); r2 = rt.rm_; // Be careful to always use shifted_branch_offset only just before the // branch instruction, as the location will be remember for patching the @@ -2035,6 +2039,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs, // Be careful to always use shifted_branch_offset only just before the // branch instruction, as the location will be remember for patching the // target. + BlockTrampolinePoolScope block_trampoline_pool(this); switch (cond) { case cc_always: offset = shifted_branch_offset(L, false); @@ -2271,67 +2276,70 @@ void MacroAssembler::BranchAndLinkShort(int16_t offset, Condition cond, li(r2, rt); } - switch (cond) { - case cc_always: - bal(offset); - break; - case eq: - bne(rs, r2, 2); - nop(); - bal(offset); - break; - case ne: - beq(rs, r2, 2); - nop(); - bal(offset); - break; + { + BlockTrampolinePoolScope block_trampoline_pool(this); + switch (cond) { + case cc_always: + bal(offset); + break; + case eq: + bne(rs, r2, 2); + nop(); + bal(offset); + break; + case ne: + beq(rs, r2, 2); + nop(); + bal(offset); + break; - // Signed comparison. - case greater: - slt(scratch, r2, rs); - addiu(scratch, scratch, -1); - bgezal(scratch, offset); - break; - case greater_equal: - slt(scratch, rs, r2); - addiu(scratch, scratch, -1); - bltzal(scratch, offset); - break; - case less: - slt(scratch, rs, r2); - addiu(scratch, scratch, -1); - bgezal(scratch, offset); - break; - case less_equal: - slt(scratch, r2, rs); - addiu(scratch, scratch, -1); - bltzal(scratch, offset); - break; + // Signed comparison. + case greater: + slt(scratch, r2, rs); + addiu(scratch, scratch, -1); + bgezal(scratch, offset); + break; + case greater_equal: + slt(scratch, rs, r2); + addiu(scratch, scratch, -1); + bltzal(scratch, offset); + break; + case less: + slt(scratch, rs, r2); + addiu(scratch, scratch, -1); + bgezal(scratch, offset); + break; + case less_equal: + slt(scratch, r2, rs); + addiu(scratch, scratch, -1); + bltzal(scratch, offset); + break; - // Unsigned comparison. - case Ugreater: - sltu(scratch, r2, rs); - addiu(scratch, scratch, -1); - bgezal(scratch, offset); - break; - case Ugreater_equal: - sltu(scratch, rs, r2); - addiu(scratch, scratch, -1); - bltzal(scratch, offset); - break; - case Uless: - sltu(scratch, rs, r2); - addiu(scratch, scratch, -1); - bgezal(scratch, offset); - break; - case Uless_equal: - sltu(scratch, r2, rs); - addiu(scratch, scratch, -1); - bltzal(scratch, offset); - break; + // Unsigned comparison. + case Ugreater: + sltu(scratch, r2, rs); + addiu(scratch, scratch, -1); + bgezal(scratch, offset); + break; + case Ugreater_equal: + sltu(scratch, rs, r2); + addiu(scratch, scratch, -1); + bltzal(scratch, offset); + break; + case Uless: + sltu(scratch, rs, r2); + addiu(scratch, scratch, -1); + bgezal(scratch, offset); + break; + case Uless_equal: + sltu(scratch, r2, rs); + addiu(scratch, scratch, -1); + bltzal(scratch, offset); + break; - default: - UNREACHABLE(); + default: + UNREACHABLE(); + } } // Emit a nop in the branch delay slot if required. if (bdslot == PROTECT) @@ -2353,7 +2361,7 @@ void MacroAssembler::BranchAndLinkShort(Label* L, Condition cond, Register rs, BranchDelaySlot bdslot) { BRANCH_ARGS_CHECK(cond, rs, rt); - int32_t offset; + int32_t offset = 0; Register r2 = no_reg; Register scratch = at; if (rt.is_reg()) { @@ -2363,80 +2371,82 @@ void MacroAssembler::BranchAndLinkShort(Label* L, Condition cond, Register rs, li(r2, rt); } - switch (cond) { - case cc_always: - offset = shifted_branch_offset(L, false); - bal(offset); - break; - case eq: - bne(rs, r2, 2); - nop(); - offset = shifted_branch_offset(L, false); - bal(offset); - break; - case ne: - beq(rs, r2, 2); - nop(); - offset = shifted_branch_offset(L, false); - bal(offset); - break; + { + BlockTrampolinePoolScope block_trampoline_pool(this); + switch (cond) { + case cc_always: + offset = shifted_branch_offset(L, false); + bal(offset); + break; + case eq: + bne(rs, r2, 2); + nop(); + offset = shifted_branch_offset(L, false); + bal(offset); + break; + case ne: + beq(rs, r2, 2); + nop(); + offset = shifted_branch_offset(L, false); + bal(offset); + break; - // Signed comparison. - case greater: - slt(scratch, r2, rs); - addiu(scratch, scratch, -1); - offset = shifted_branch_offset(L, false); - bgezal(scratch, offset); - break; - case greater_equal: - slt(scratch, rs, r2); - addiu(scratch, scratch, -1); - offset = shifted_branch_offset(L, false); - bltzal(scratch, offset); - break; - case less: - slt(scratch, rs, r2); - addiu(scratch, scratch, -1); - offset = shifted_branch_offset(L, false); - bgezal(scratch, offset); - break; - case less_equal: - slt(scratch, r2, rs); - addiu(scratch, scratch, -1); - offset = shifted_branch_offset(L, false); - bltzal(scratch, offset); - break; + // Signed comparison. + case greater: + slt(scratch, r2, rs); + addiu(scratch, scratch, -1); + offset = shifted_branch_offset(L, false); + bgezal(scratch, offset); + break; + case greater_equal: + slt(scratch, rs, r2); + addiu(scratch, scratch, -1); + offset = shifted_branch_offset(L, false); + bltzal(scratch, offset); + break; + case less: + slt(scratch, rs, r2); + addiu(scratch, scratch, -1); + offset = shifted_branch_offset(L, false); + bgezal(scratch, offset); + break; + case less_equal: + slt(scratch, r2, rs); + addiu(scratch, scratch, -1); + offset = shifted_branch_offset(L, false); + bltzal(scratch, offset); + break; - // Unsigned comparison. - case Ugreater: - sltu(scratch, r2, rs); - addiu(scratch, scratch, -1); - offset = shifted_branch_offset(L, false); - bgezal(scratch, offset); - break; - case Ugreater_equal: - sltu(scratch, rs, r2); - addiu(scratch, scratch, -1); - offset = shifted_branch_offset(L, false); - bltzal(scratch, offset); - break; - case Uless: - sltu(scratch, rs, r2); - addiu(scratch, scratch, -1); - offset = shifted_branch_offset(L, false); - bgezal(scratch, offset); - break; - case Uless_equal: - sltu(scratch, r2, rs); - addiu(scratch, scratch, -1); - offset = shifted_branch_offset(L, false); - bltzal(scratch, offset); - break; + // Unsigned comparison. + case Ugreater: + sltu(scratch, r2, rs); + addiu(scratch, scratch, -1); + offset = shifted_branch_offset(L, false); + bgezal(scratch, offset); + break; + case Ugreater_equal: + sltu(scratch, rs, r2); + addiu(scratch, scratch, -1); + offset = shifted_branch_offset(L, false); + bltzal(scratch, offset); + break; + case Uless: + sltu(scratch, rs, r2); + addiu(scratch, scratch, -1); + offset = shifted_branch_offset(L, false); + bgezal(scratch, offset); + break; + case Uless_equal: + sltu(scratch, r2, rs); + addiu(scratch, scratch, -1); + offset = shifted_branch_offset(L, false); + bltzal(scratch, offset); + break; - default: - UNREACHABLE(); + default: + UNREACHABLE(); + } } - // Check that offset could actually hold on an int16_t. ASSERT(is_int16(offset)); @@ -2992,13 +3002,12 @@ void MacroAssembler::Allocate(int object_size, } -void MacroAssembler::AllocateInNewSpace(Register object_size, - Register result, - Register scratch1, - Register scratch2, - Label* gc_required, - AllocationFlags flags) { - ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0); +void MacroAssembler::Allocate(Register object_size, + Register result, + Register scratch1, + Register scratch2, + Label* gc_required, + AllocationFlags flags) { if (!FLAG_inline_new) { if (emit_debug_code()) { // Trash the registers to simulate an allocation failure. @@ -3019,19 +3028,19 @@ void MacroAssembler::AllocateInNewSpace(Register object_size, // Check relative positions of allocation top and limit addresses. // ARM adds additional checks to make sure the ldm instruction can be // used. On MIPS we don't have ldm so we don't need additional checks either. - ExternalReference new_space_allocation_top = - ExternalReference::new_space_allocation_top_address(isolate()); - ExternalReference new_space_allocation_limit = - ExternalReference::new_space_allocation_limit_address(isolate()); + ExternalReference allocation_top = + AllocationUtils::GetAllocationTopReference(isolate(), flags); + ExternalReference allocation_limit = + AllocationUtils::GetAllocationLimitReference(isolate(), flags); intptr_t top = - reinterpret_cast<intptr_t>(new_space_allocation_top.address()); + reinterpret_cast<intptr_t>(allocation_top.address()); intptr_t limit = - reinterpret_cast<intptr_t>(new_space_allocation_limit.address()); + reinterpret_cast<intptr_t>(allocation_limit.address()); ASSERT((limit - top) == kPointerSize); // Set up allocation top address and object size registers. Register topaddr = scratch1; - li(topaddr, Operand(new_space_allocation_top)); + li(topaddr, Operand(allocation_top)); // This code stores a temporary value in t9. if ((flags & RESULT_CONTAINS_TOP) == 0) { @@ -3110,12 +3119,12 @@ void MacroAssembler::AllocateTwoByteString(Register result, And(scratch1, scratch1, Operand(~kObjectAlignmentMask)); // Allocate two-byte string in new space. - AllocateInNewSpace(scratch1, - result, - scratch2, - scratch3, - gc_required, - TAG_OBJECT); + Allocate(scratch1, + result, + scratch2, + scratch3, + gc_required, + TAG_OBJECT); // Set the map, length and hash field. InitializeNewString(result, @@ -3140,12 +3149,12 @@ void MacroAssembler::AllocateAsciiString(Register result, And(scratch1, scratch1, Operand(~kObjectAlignmentMask)); // Allocate ASCII string in new space. - AllocateInNewSpace(scratch1, - result, - scratch2, - scratch3, - gc_required, - TAG_OBJECT); + Allocate(scratch1, + result, + scratch2, + scratch3, + gc_required, + TAG_OBJECT); // Set the map, length and hash field. InitializeNewString(result, @@ -5505,7 +5514,6 @@ bool AreAliased(Register r1, Register r2, Register r3, Register r4) { CodePatcher::CodePatcher(byte* address, int instructions) : address_(address), - instructions_(instructions), size_(instructions * Assembler::kInstrSize), masm_(NULL, address, size_ + Assembler::kGap) { // Create a new macro assembler pointing to the address of the code to patch. diff --git a/deps/v8/src/mips/macro-assembler-mips.h b/deps/v8/src/mips/macro-assembler-mips.h index e4cf3bcb7..125cc8aaf 100644 --- a/deps/v8/src/mips/macro-assembler-mips.h +++ b/deps/v8/src/mips/macro-assembler-mips.h @@ -491,12 +491,12 @@ class MacroAssembler: public Assembler { Label* gc_required, AllocationFlags flags); - void AllocateInNewSpace(Register object_size, - Register result, - Register scratch1, - Register scratch2, - Label* gc_required, - AllocationFlags flags); + void Allocate(Register object_size, + Register result, + Register scratch1, + Register scratch2, + Label* gc_required, + AllocationFlags flags); // Undo allocation in new space. The object passed and objects allocated after // it will no longer be allocated. The caller must make sure that no pointers @@ -1565,7 +1565,6 @@ class CodePatcher { private: byte* address_; // The address of the code being patched. - int instructions_; // Number of instructions of the expected patch size. int size_; // Number of bytes of the expected patch size. MacroAssembler masm_; // Macro assembler used to generate the code. }; diff --git a/deps/v8/src/mips/regexp-macro-assembler-mips.cc b/deps/v8/src/mips/regexp-macro-assembler-mips.cc index 036cbb13e..2fbc0eaa5 100644 --- a/deps/v8/src/mips/regexp-macro-assembler-mips.cc +++ b/deps/v8/src/mips/regexp-macro-assembler-mips.cc @@ -1005,6 +1005,7 @@ void RegExpMacroAssemblerMIPS::PushBacktrack(Label* label) { int target = label->pos(); __ li(a0, Operand(target + Code::kHeaderSize - kHeapObjectTag)); } else { + Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); Label after_constant; __ Branch(&after_constant); int offset = masm_->pc_offset(); diff --git a/deps/v8/src/mips/simulator-mips.cc b/deps/v8/src/mips/simulator-mips.cc index be9f369d0..5eb79eb78 100644 --- a/deps/v8/src/mips/simulator-mips.cc +++ b/deps/v8/src/mips/simulator-mips.cc @@ -132,8 +132,8 @@ void MipsDebugger::Stop(Instruction* instr) { ASSERT(msg != NULL); // Update this stop description. - if (!watched_stops[code].desc) { - watched_stops[code].desc = msg; + if (!watched_stops_[code].desc) { + watched_stops_[code].desc = msg; } if (strlen(msg) > 0) { @@ -163,8 +163,8 @@ void MipsDebugger::Stop(Instruction* instr) { char* msg = *reinterpret_cast<char**>(sim_->get_pc() + Instruction::kInstrSize); // Update this stop description. - if (!sim_->watched_stops[code].desc) { - sim_->watched_stops[code].desc = msg; + if (!sim_->watched_stops_[code].desc) { + sim_->watched_stops_[code].desc = msg; } PrintF("Simulator hit %s (%u)\n", msg, code); sim_->set_pc(sim_->get_pc() + 2 * Instruction::kInstrSize); @@ -513,7 +513,7 @@ void MipsDebugger::Debug() { int32_t words; if (argc == next_arg) { words = 10; - } else if (argc == next_arg + 1) { + } else { if (!GetValue(argv[next_arg], &words)) { words = 10; } @@ -1636,33 +1636,33 @@ bool Simulator::IsStopInstruction(Instruction* instr) { bool Simulator::IsEnabledStop(uint32_t code) { ASSERT(code <= kMaxStopCode); ASSERT(code > kMaxWatchpointCode); - return !(watched_stops[code].count & kStopDisabledBit); + return !(watched_stops_[code].count & kStopDisabledBit); } void Simulator::EnableStop(uint32_t code) { if (!IsEnabledStop(code)) { - watched_stops[code].count &= ~kStopDisabledBit; + watched_stops_[code].count &= ~kStopDisabledBit; } } void Simulator::DisableStop(uint32_t code) { if (IsEnabledStop(code)) { - watched_stops[code].count |= kStopDisabledBit; + watched_stops_[code].count |= kStopDisabledBit; } } void Simulator::IncreaseStopCounter(uint32_t code) { ASSERT(code <= kMaxStopCode); - if ((watched_stops[code].count & ~(1 << 31)) == 0x7fffffff) { + if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) { PrintF("Stop counter for code %i has overflowed.\n" "Enabling this code and reseting the counter to 0.\n", code); - watched_stops[code].count = 0; + watched_stops_[code].count = 0; EnableStop(code); } else { - watched_stops[code].count++; + watched_stops_[code].count++; } } @@ -1677,12 +1677,12 @@ void Simulator::PrintStopInfo(uint32_t code) { return; } const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled"; - int32_t count = watched_stops[code].count & ~kStopDisabledBit; + int32_t count = watched_stops_[code].count & ~kStopDisabledBit; // Don't print the state of unused breakpoints. if (count != 0) { - if (watched_stops[code].desc) { + if (watched_stops_[code].desc) { PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", - code, code, state, count, watched_stops[code].desc); + code, code, state, count, watched_stops_[code].desc); } else { PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n", code, code, state, count); diff --git a/deps/v8/src/mips/simulator-mips.h b/deps/v8/src/mips/simulator-mips.h index 67f595302..ed6344342 100644 --- a/deps/v8/src/mips/simulator-mips.h +++ b/deps/v8/src/mips/simulator-mips.h @@ -391,14 +391,14 @@ class Simulator { static const uint32_t kStopDisabledBit = 1 << 31; // A stop is enabled, meaning the simulator will stop when meeting the - // instruction, if bit 31 of watched_stops[code].count is unset. - // The value watched_stops[code].count & ~(1 << 31) indicates how many times + // instruction, if bit 31 of watched_stops_[code].count is unset. + // The value watched_stops_[code].count & ~(1 << 31) indicates how many times // the breakpoint was hit or gone through. struct StopCountAndDesc { uint32_t count; char* desc; }; - StopCountAndDesc watched_stops[kMaxStopCode + 1]; + StopCountAndDesc watched_stops_[kMaxStopCode + 1]; }; diff --git a/deps/v8/src/mips/stub-cache-mips.cc b/deps/v8/src/mips/stub-cache-mips.cc index d5cf6de90..da6770a14 100644 --- a/deps/v8/src/mips/stub-cache-mips.cc +++ b/deps/v8/src/mips/stub-cache-mips.cc @@ -415,7 +415,7 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, // may be clobbered. void StubCompiler::GenerateStoreField(MacroAssembler* masm, Handle<JSObject> object, - int index, + LookupResult* lookup, Handle<Map> transition, Handle<Name> name, Register receiver_reg, @@ -428,16 +428,6 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, // a0 : value. Label exit; - LookupResult lookup(masm->isolate()); - object->Lookup(*name, &lookup); - if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) { - // In sloppy mode, we could just return the value and be done. However, we - // might be in strict mode, where we have to throw. Since we cannot tell, - // go into slow case unconditionally. - __ jmp(miss_label); - return; - } - // Check that the map of the object hasn't changed. CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS : REQUIRE_EXACT_MAP; @@ -452,8 +442,9 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, // Check that we are allowed to write this. if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { JSObject* holder; - if (lookup.IsFound()) { - holder = lookup.holder(); + // holder == object indicates that no property was found. + if (lookup->holder() != *object) { + holder = lookup->holder(); } else { // Find the top object. holder = *object; @@ -461,8 +452,19 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, holder = JSObject::cast(holder->GetPrototype()); } while (holder->GetPrototype()->IsJSObject()); } - CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg, - scratch1, scratch2, name, miss_restore_name); + Register holder_reg = CheckPrototypes( + object, receiver_reg, Handle<JSObject>(holder), name_reg, + scratch1, scratch2, name, miss_restore_name); + // If no property was found, and the holder (the last object in the + // prototype chain) is in slow mode, we need to do a negative lookup on the + // holder. + if (lookup->holder() == *object && + !holder->HasFastProperties() && + !holder->IsJSGlobalProxy() && + !holder->IsJSGlobalObject()) { + GenerateDictionaryNegativeLookup( + masm, miss_restore_name, holder_reg, name, scratch1, scratch2); + } } // Stub never generated for non-global objects that require access @@ -483,6 +485,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, return; } + int index; if (!transition.is_null()) { // Update the map of the object. __ li(scratch1, Operand(transition)); @@ -498,6 +501,10 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); + index = transition->instance_descriptors()->GetFieldIndex( + transition->LastAdded()); + } else { + index = lookup->GetFieldIndex().field_index(); } // Adjust for the number of properties stored in the object. Even in the @@ -2424,6 +2431,12 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object, // Check that the object is a symbol. __ GetObjectType(a1, a1, a3); __ Branch(&miss, ne, a3, Operand(SYMBOL_TYPE)); + // Check that the maps starting from the prototype haven't changed. + GenerateDirectLoadGlobalFunctionPrototype( + masm(), Context::SYMBOL_FUNCTION_INDEX, a0, &miss); + CheckPrototypes( + Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))), + a0, holder, a3, a1, t0, name, &miss); break; case NUMBER_CHECK: { @@ -3010,7 +3023,7 @@ Handle<Code> ConstructStubCompiler::CompileConstructStub( __ Check(eq, "Instance size of initial map changed.", a3, Operand(instance_size >> kPointerSizeLog2)); #endif - __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS); + __ Allocate(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS); // Allocated the JSObject, now initialize the fields. Map is set to initial // map and properties and elements are set to empty fixed array. diff --git a/deps/v8/src/mirror-debugger.js b/deps/v8/src/mirror-debugger.js index 7f1a05aed..e1fd872f3 100644 --- a/deps/v8/src/mirror-debugger.js +++ b/deps/v8/src/mirror-debugger.js @@ -638,7 +638,7 @@ ObjectMirror.prototype.propertyNames = function(kind, limit) { // Find all the named properties. if (kind & PropertyKind.Named) { // Get the local property names. - propertyNames = %GetLocalPropertyNames(this.value_); + propertyNames = %GetLocalPropertyNames(this.value_, true); total += propertyNames.length; // Get names for named interceptor properties if any. diff --git a/deps/v8/src/object-observe.js b/deps/v8/src/object-observe.js index b35f547ed..bfb4a6545 100644 --- a/deps/v8/src/object-observe.js +++ b/deps/v8/src/object-observe.js @@ -117,6 +117,9 @@ function ObjectUnobserve(object, callback) { } function EnqueueChangeRecord(changeRecord, observers) { + // TODO(rossberg): adjust once there is a story for symbols vs proxies. + if (IS_SYMBOL(changeRecord.name)) return; + for (var i = 0; i < observers.length; i++) { var observer = observers[i]; var observerInfo = observerInfoMap.get(observer); diff --git a/deps/v8/src/objects-debug.cc b/deps/v8/src/objects-debug.cc index 82a71a5ff..44cab53cc 100644 --- a/deps/v8/src/objects-debug.cc +++ b/deps/v8/src/objects-debug.cc @@ -195,6 +195,9 @@ void HeapObject::HeapObjectVerify() { case JS_MESSAGE_OBJECT_TYPE: JSMessageObject::cast(this)->JSMessageObjectVerify(); break; + case JS_ARRAY_BUFFER_TYPE: + JSArrayBuffer::cast(this)->JSArrayBufferVerify(); + break; #define MAKE_STRUCT_CASE(NAME, Name, name) \ case NAME##_TYPE: \ @@ -220,6 +223,7 @@ void Symbol::SymbolVerify() { CHECK(IsSymbol()); CHECK(HasHashCode()); CHECK_GT(Hash(), 0); + CHECK(name()->IsUndefined() || name()->IsString()); } @@ -711,6 +715,14 @@ void JSFunctionProxy::JSFunctionProxyVerify() { VerifyPointer(construct_trap()); } +void JSArrayBuffer::JSArrayBufferVerify() { + CHECK(IsJSArrayBuffer()); + JSObjectVerify(); + VerifyPointer(byte_length()); + CHECK(byte_length()->IsSmi() || byte_length()->IsHeapNumber() + || byte_length()->IsUndefined()); +} + void Foreign::ForeignVerify() { CHECK(IsForeign()); diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index 02542612b..ec03405fd 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -674,6 +674,7 @@ bool Object::IsBoolean() { TYPE_CHECKER(JSArray, JS_ARRAY_TYPE) +TYPE_CHECKER(JSArrayBuffer, JS_ARRAY_BUFFER_TYPE) TYPE_CHECKER(JSRegExp, JS_REGEXP_TYPE) @@ -1490,13 +1491,17 @@ MaybeObject* JSObject::AddFastPropertyUsingMap(Map* map) { bool JSObject::TryTransitionToField(Handle<JSObject> object, Handle<Name> key) { if (!object->map()->HasTransitionArray()) return false; - Handle<TransitionArray> transitions(object->map()->transitions()); - int transition = transitions->Search(*key); - if (transition == TransitionArray::kNotFound) return false; - PropertyDetails target_details = transitions->GetTargetDetails(transition); - if (target_details.type() != FIELD) return false; - if (target_details.attributes() != NONE) return false; - Handle<Map> target(transitions->GetTarget(transition)); + Handle<Map> target; + { + AssertNoAllocation no_allocation; + TransitionArray* transitions = object->map()->transitions(); + int transition = transitions->Search(*key); + if (transition == TransitionArray::kNotFound) return false; + PropertyDetails target_details = transitions->GetTargetDetails(transition); + if (target_details.type() != FIELD) return false; + if (target_details.attributes() != NONE) return false; + target = Handle<Map>(transitions->GetTarget(transition)); + } JSObject::AddFastPropertyUsingMap(object, target); return true; } @@ -1558,6 +1563,8 @@ int JSObject::GetHeaderSize() { return JSDate::kSize; case JS_ARRAY_TYPE: return JSArray::kSize; + case JS_ARRAY_BUFFER_TYPE: + return JSArrayBuffer::kSize; case JS_SET_TYPE: return JSSet::kSize; case JS_MAP_TYPE: @@ -2444,6 +2451,7 @@ CAST_ACCESSOR(JSGlobalObject) CAST_ACCESSOR(JSBuiltinsObject) CAST_ACCESSOR(Code) CAST_ACCESSOR(JSArray) +CAST_ACCESSOR(JSArrayBuffer) CAST_ACCESSOR(JSRegExp) CAST_ACCESSOR(JSProxy) CAST_ACCESSOR(JSFunctionProxy) @@ -2500,11 +2508,17 @@ void Name::set_hash_field(uint32_t value) { bool Name::Equals(Name* other) { if (other == this) return true; - if (this->IsUniqueName() && other->IsUniqueName()) return false; + if (this->IsSymbol() || other->IsSymbol() || + (this->IsInternalizedString() && other->IsInternalizedString())) { + return false; + } return String::cast(this)->SlowEquals(String::cast(other)); } +ACCESSORS(Symbol, name, Object, kNameOffset) + + bool String::Equals(String* other) { if (other == this) return true; if (this->IsInternalizedString() && other->IsInternalizedString()) { @@ -4125,9 +4139,12 @@ TransitionArray* Map::transitions() { void Map::set_transitions(TransitionArray* transition_array, WriteBarrierMode mode) { - // In release mode, only run this code if verify_heap is on. - if (Heap::ShouldZapGarbage() && HasTransitionArray()) { - CHECK(transitions() != transition_array); + // Transition arrays are not shared. When one is replaced, it should not + // keep referenced objects alive, so we zap it. + // When there is another reference to the array somewhere (e.g. a handle), + // not zapping turns from a waste of memory into a source of crashes. + if (HasTransitionArray()) { + ASSERT(transitions() != transition_array); ZapTransitions(); } @@ -4505,6 +4522,7 @@ BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, dont_optimize, kDontOptimize) BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, dont_inline, kDontInline) BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, dont_cache, kDontCache) +BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_generator, kIsGenerator) void SharedFunctionInfo::BeforeVisitingPointers() { if (IsInobjectSlackTrackingInProgress()) DetachInitialMap(); @@ -5121,6 +5139,21 @@ bool Code::contains(byte* inner_pointer) { ACCESSORS(JSArray, length, Object, kLengthOffset) +void* JSArrayBuffer::backing_store() { + intptr_t ptr = READ_INTPTR_FIELD(this, kBackingStoreOffset); + return reinterpret_cast<void*>(ptr); +} + + +void JSArrayBuffer::set_backing_store(void* value, WriteBarrierMode mode) { + intptr_t ptr = reinterpret_cast<intptr_t>(value); + WRITE_INTPTR_FIELD(this, kBackingStoreOffset, ptr); +} + + +ACCESSORS(JSArrayBuffer, byte_length, Object, kByteLengthOffset) + + ACCESSORS(JSRegExp, data, Object, kDataOffset) diff --git a/deps/v8/src/objects-printer.cc b/deps/v8/src/objects-printer.cc index 4522ee43e..834223261 100644 --- a/deps/v8/src/objects-printer.cc +++ b/deps/v8/src/objects-printer.cc @@ -184,6 +184,8 @@ void HeapObject::HeapObjectPrint(FILE* out) { case JS_GLOBAL_PROPERTY_CELL_TYPE: JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellPrint(out); break; + case JS_ARRAY_BUFFER_TYPE: + JSArrayBuffer::cast(this)->JSArrayBufferPrint(out); #define MAKE_STRUCT_CASE(NAME, Name, name) \ case NAME##_TYPE: \ Name::cast(this)->Name##Print(out); \ @@ -552,6 +554,9 @@ static const char* TypeToString(InstanceType type) { void Symbol::SymbolPrint(FILE* out) { HeapObject::PrintHeader(out, "Symbol"); PrintF(out, " - hash: %d\n", Hash()); + PrintF(out, " - name: "); + name()->ShortPrint(); + PrintF(out, "\n"); } @@ -792,6 +797,16 @@ void JSWeakMap::JSWeakMapPrint(FILE* out) { } +void JSArrayBuffer::JSArrayBufferPrint(FILE* out) { + HeapObject::PrintHeader(out, "JSArrayBuffer"); + PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map())); + PrintF(out, " - backing_store = -0x%p\n", backing_store()); + PrintF(out, " - byte_length = "); + byte_length()->ShortPrint(out); + PrintF(out, "\n"); +} + + void JSFunction::JSFunctionPrint(FILE* out) { HeapObject::PrintHeader(out, "Function"); PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map())); diff --git a/deps/v8/src/objects-visiting-inl.h b/deps/v8/src/objects-visiting-inl.h index beb07b564..6a64cbf80 100644 --- a/deps/v8/src/objects-visiting-inl.h +++ b/deps/v8/src/objects-visiting-inl.h @@ -49,6 +49,11 @@ void StaticNewSpaceVisitor<StaticVisitor>::Initialize() { SlicedString::BodyDescriptor, int>::Visit); + table_.Register(kVisitSymbol, + &FixedBodyVisitor<StaticVisitor, + Symbol::BodyDescriptor, + int>::Visit); + table_.Register(kVisitFixedArray, &FlexibleBodyVisitor<StaticVisitor, FixedArray::BodyDescriptor, @@ -110,6 +115,11 @@ void StaticMarkingVisitor<StaticVisitor>::Initialize() { SlicedString::BodyDescriptor, void>::Visit); + table_.Register(kVisitSymbol, + &FixedBodyVisitor<StaticVisitor, + Symbol::BodyDescriptor, + void>::Visit); + table_.Register(kVisitFixedArray, &FixedArrayVisitor::Visit); table_.Register(kVisitFixedDoubleArray, &DataObjectVisitor::Visit); @@ -397,7 +407,7 @@ void StaticMarkingVisitor<StaticVisitor>::MarkMapContents( } // Since descriptor arrays are potentially shared, ensure that only the - // descriptors that appeared for this map are marked. The first time a + // descriptors that belong to this map are marked. The first time a // non-empty descriptor array is marked, its header is also visited. The slot // holding the descriptor array will be implicitly recorded when the pointer // fields of this map are visited. @@ -410,13 +420,6 @@ void StaticMarkingVisitor<StaticVisitor>::MarkMapContents( } int start = 0; int end = map->NumberOfOwnDescriptors(); - Object* back_pointer = map->GetBackPointer(); - if (!back_pointer->IsUndefined()) { - Map* parent_map = Map::cast(back_pointer); - if (descriptors == parent_map->instance_descriptors()) { - start = parent_map->NumberOfOwnDescriptors(); - } - } if (start < end) { StaticVisitor::VisitPointers(heap, descriptors->GetDescriptorStartSlot(start), diff --git a/deps/v8/src/objects-visiting.cc b/deps/v8/src/objects-visiting.cc index 088f5ebde..fa53562bd 100644 --- a/deps/v8/src/objects-visiting.cc +++ b/deps/v8/src/objects-visiting.cc @@ -129,9 +129,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( Foreign::kSize); case SYMBOL_TYPE: - return GetVisitorIdForSize(kVisitDataObject, - kVisitDataObjectGeneric, - Symbol::kSize); + return kVisitSymbol; case FILLER_TYPE: return kVisitDataObjectGeneric; @@ -146,6 +144,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( case JS_GLOBAL_OBJECT_TYPE: case JS_BUILTINS_OBJECT_TYPE: case JS_MESSAGE_OBJECT_TYPE: + case JS_ARRAY_BUFFER_TYPE: return GetVisitorIdForSize(kVisitJSObject, kVisitJSObjectGeneric, instance_size); diff --git a/deps/v8/src/objects-visiting.h b/deps/v8/src/objects-visiting.h index 9b2422ca2..d4a2ed2d1 100644 --- a/deps/v8/src/objects-visiting.h +++ b/deps/v8/src/objects-visiting.h @@ -84,6 +84,7 @@ class StaticVisitorBase : public AllStatic { V(StructGeneric) \ V(ConsString) \ V(SlicedString) \ + V(Symbol) \ V(Oddball) \ V(Code) \ V(Map) \ diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 00d00d5ee..8f03b1043 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -98,6 +98,10 @@ MaybeObject* Object::ToObject() { Isolate* isolate = HeapObject::cast(this)->GetIsolate(); Context* native_context = isolate->context()->native_context(); return CreateJSValue(native_context->string_function(), this); + } else if (IsSymbol()) { + Isolate* isolate = HeapObject::cast(this)->GetIsolate(); + Context* native_context = isolate->context()->native_context(); + return CreateJSValue(native_context->symbol_function(), this); } // Throw a type error. @@ -126,10 +130,10 @@ void Object::Lookup(Name* name, LookupResult* result) { holder = native_context->number_function()->instance_prototype(); } else if (IsString()) { holder = native_context->string_function()->instance_prototype(); + } else if (IsSymbol()) { + holder = native_context->symbol_function()->instance_prototype(); } else if (IsBoolean()) { holder = native_context->boolean_function()->instance_prototype(); - } else if (IsSymbol()) { - holder = native_context->symbol_delegate(); } else { Isolate::Current()->PushStackTraceAndDie( 0xDEAD0000, this, JSReceiver::cast(this)->map(), 0xDEAD0001); @@ -375,6 +379,9 @@ MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw, Handle<Object> receiver(receiver_raw, isolate); Handle<Object> name(name_raw, isolate); + // TODO(rossberg): adjust once there is a story for symbols vs proxies. + if (name->IsSymbol()) return isolate->heap()->undefined_value(); + Handle<Object> args[] = { receiver, name }; Handle<Object> result = CallTrap( "get", isolate->derived_get_trap(), ARRAY_SIZE(args), args); @@ -756,7 +763,7 @@ MaybeObject* Object::GetProperty(Object* receiver, // holder in the prototype chain. // Proxy handlers do not use the proxy's prototype, so we can skip this. if (!result->IsHandler()) { - Object* last = result->IsProperty() && !receiver->IsSymbol() + Object* last = result->IsProperty() ? result->holder() : Object::cast(heap->null_value()); ASSERT(this != this->GetPrototype(isolate)); @@ -837,10 +844,10 @@ MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) { holder = native_context->number_function()->instance_prototype(); } else if (holder->IsString()) { holder = native_context->string_function()->instance_prototype(); + } else if (holder->IsSymbol()) { + holder = native_context->symbol_function()->instance_prototype(); } else if (holder->IsBoolean()) { holder = native_context->boolean_function()->instance_prototype(); - } else if (holder->IsSymbol()) { - holder = native_context->symbol_delegate(); } else if (holder->IsJSProxy()) { return JSProxy::cast(holder)->GetElementWithHandler(receiver, index); } else { @@ -900,6 +907,9 @@ Object* Object::GetPrototype(Isolate* isolate) { if (heap_object->IsString()) { return context->string_function()->instance_prototype(); } + if (heap_object->IsSymbol()) { + return context->symbol_function()->instance_prototype(); + } if (heap_object->IsBoolean()) { return context->boolean_function()->instance_prototype(); } else { @@ -908,16 +918,6 @@ Object* Object::GetPrototype(Isolate* isolate) { } -Object* Object::GetDelegate(Isolate* isolate) { - if (IsSymbol()) { - Heap* heap = Symbol::cast(this)->GetHeap(); - Context* context = heap->isolate()->context()->native_context(); - return context->symbol_delegate(); - } - return GetPrototype(isolate); -} - - MaybeObject* Object::GetHash(CreationFlag flag) { // The object is either a number, a name, an odd-ball, // a real JS object, or a Harmony proxy. @@ -1467,9 +1467,16 @@ void HeapObject::HeapObjectShortPrint(StringStream* accumulator) { accumulator->Add("<Odd Oddball>"); break; } - case SYMBOL_TYPE: - accumulator->Add("<Symbol: %d>", Symbol::cast(this)->Hash()); + case SYMBOL_TYPE: { + Symbol* symbol = Symbol::cast(this); + accumulator->Add("<Symbol: %d", symbol->Hash()); + if (!symbol->name()->IsUndefined()) { + accumulator->Add(" "); + String::cast(symbol->name())->StringShortPrint(accumulator); + } + accumulator->Add(">"); break; + } case HEAP_NUMBER_TYPE: accumulator->Add("<Number: "); HeapNumber::cast(this)->HeapNumberPrint(accumulator); @@ -1543,6 +1550,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size, case JS_VALUE_TYPE: case JS_DATE_TYPE: case JS_ARRAY_TYPE: + case JS_ARRAY_BUFFER_TYPE: case JS_SET_TYPE: case JS_MAP_TYPE: case JS_WEAK_MAP_TYPE: @@ -1579,6 +1587,8 @@ void HeapObject::IterateBody(InstanceType type, int object_size, JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v); break; case SYMBOL_TYPE: + Symbol::BodyDescriptor::IterateBody(this, v); + break; case HEAP_NUMBER_TYPE: case FILLER_TYPE: case BYTE_ARRAY_TYPE: @@ -1728,7 +1738,7 @@ MaybeObject* JSObject::AddFastProperty(Name* name, // hidden strings) and is not a real identifier. // Normalize the object if it will have too many fast properties. Isolate* isolate = GetHeap()->isolate(); - if ((!IsIdentifier(isolate->unicode_cache(), name) + if ((!name->IsSymbol() && !IsIdentifier(isolate->unicode_cache(), name) && name != isolate->heap()->hidden_string()) || (map()->unused_property_fields() == 0 && TooManyFastProperties(properties()->length(), store_mode))) { @@ -2755,6 +2765,9 @@ bool JSProxy::HasPropertyWithHandler(Name* name_raw) { Handle<Object> receiver(this, isolate); Handle<Object> name(name_raw, isolate); + // TODO(rossberg): adjust once there is a story for symbols vs proxies. + if (name->IsSymbol()) return false; + Handle<Object> args[] = { name }; Handle<Object> result = CallTrap( "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args); @@ -2776,6 +2789,9 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler( Handle<Object> name(name_raw, isolate); Handle<Object> value(value_raw, isolate); + // TODO(rossberg): adjust once there is a story for symbols vs proxies. + if (name->IsSymbol()) return *value; + Handle<Object> args[] = { receiver, name, value }; CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args); if (isolate->has_pending_exception()) return Failure::Exception(); @@ -2798,6 +2814,12 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyViaPrototypesWithHandler( Handle<Object> value(value_raw, isolate); Handle<Object> handler(this->handler(), isolate); // Trap might morph proxy. + // TODO(rossberg): adjust once there is a story for symbols vs proxies. + if (name->IsSymbol()) { + *done = false; + return isolate->heap()->the_hole_value(); + } + *done = true; // except where redefined... Handle<Object> args[] = { name }; Handle<Object> result = proxy->CallTrap( @@ -2806,7 +2828,7 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyViaPrototypesWithHandler( if (result->IsUndefined()) { *done = false; - return GetHeap()->the_hole_value(); + return isolate->heap()->the_hole_value(); } // Emulate [[GetProperty]] semantics for proxies. @@ -2887,6 +2909,9 @@ MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler( Handle<JSProxy> receiver(this); Handle<Object> name(name_raw, isolate); + // TODO(rossberg): adjust once there is a story for symbols vs proxies. + if (name->IsSymbol()) return isolate->heap()->false_value(); + Handle<Object> args[] = { name }; Handle<Object> result = CallTrap( "delete", Handle<Object>(), ARRAY_SIZE(args), args); @@ -2927,6 +2952,9 @@ MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler( Handle<JSReceiver> receiver(receiver_raw); Handle<Object> name(name_raw, isolate); + // TODO(rossberg): adjust once there is a story for symbols vs proxies. + if (name->IsSymbol()) return ABSENT; + Handle<Object> args[] = { name }; Handle<Object> result = CallTrap( "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args); @@ -4665,6 +4693,145 @@ MaybeObject* JSObject::PreventExtensions() { } +MUST_USE_RESULT MaybeObject* JSObject::DeepCopy(Isolate* isolate) { + StackLimitCheck check(isolate); + if (check.HasOverflowed()) return isolate->StackOverflow(); + + Heap* heap = isolate->heap(); + Object* result; + { MaybeObject* maybe_result = heap->CopyJSObject(this); + if (!maybe_result->ToObject(&result)) return maybe_result; + } + JSObject* copy = JSObject::cast(result); + + // Deep copy local properties. + if (copy->HasFastProperties()) { + FixedArray* properties = copy->properties(); + for (int i = 0; i < properties->length(); i++) { + Object* value = properties->get(i); + if (value->IsJSObject()) { + JSObject* js_object = JSObject::cast(value); + { MaybeObject* maybe_result = js_object->DeepCopy(isolate); + if (!maybe_result->ToObject(&result)) return maybe_result; + } + properties->set(i, result); + } + } + int nof = copy->map()->inobject_properties(); + for (int i = 0; i < nof; i++) { + Object* value = copy->InObjectPropertyAt(i); + if (value->IsJSObject()) { + JSObject* js_object = JSObject::cast(value); + { MaybeObject* maybe_result = js_object->DeepCopy(isolate); + if (!maybe_result->ToObject(&result)) return maybe_result; + } + copy->InObjectPropertyAtPut(i, result); + } + } + } else { + { MaybeObject* maybe_result = + heap->AllocateFixedArray(copy->NumberOfLocalProperties()); + if (!maybe_result->ToObject(&result)) return maybe_result; + } + FixedArray* names = FixedArray::cast(result); + copy->GetLocalPropertyNames(names, 0); + for (int i = 0; i < names->length(); i++) { + ASSERT(names->get(i)->IsString()); + String* key_string = String::cast(names->get(i)); + PropertyAttributes attributes = + copy->GetLocalPropertyAttribute(key_string); + // Only deep copy fields from the object literal expression. + // In particular, don't try to copy the length attribute of + // an array. + if (attributes != NONE) continue; + Object* value = + copy->GetProperty(key_string, &attributes)->ToObjectUnchecked(); + if (value->IsJSObject()) { + JSObject* js_object = JSObject::cast(value); + { MaybeObject* maybe_result = js_object->DeepCopy(isolate); + if (!maybe_result->ToObject(&result)) return maybe_result; + } + { MaybeObject* maybe_result = + // Creating object copy for literals. No strict mode needed. + copy->SetProperty(key_string, result, NONE, kNonStrictMode); + if (!maybe_result->ToObject(&result)) return maybe_result; + } + } + } + } + + // Deep copy local elements. + // Pixel elements cannot be created using an object literal. + ASSERT(!copy->HasExternalArrayElements()); + switch (copy->GetElementsKind()) { + case FAST_SMI_ELEMENTS: + case FAST_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: + case FAST_HOLEY_ELEMENTS: { + FixedArray* elements = FixedArray::cast(copy->elements()); + if (elements->map() == heap->fixed_cow_array_map()) { + isolate->counters()->cow_arrays_created_runtime()->Increment(); +#ifdef DEBUG + for (int i = 0; i < elements->length(); i++) { + ASSERT(!elements->get(i)->IsJSObject()); + } +#endif + } else { + for (int i = 0; i < elements->length(); i++) { + Object* value = elements->get(i); + ASSERT(value->IsSmi() || + value->IsTheHole() || + (IsFastObjectElementsKind(copy->GetElementsKind()))); + if (value->IsJSObject()) { + JSObject* js_object = JSObject::cast(value); + { MaybeObject* maybe_result = js_object->DeepCopy(isolate); + if (!maybe_result->ToObject(&result)) return maybe_result; + } + elements->set(i, result); + } + } + } + break; + } + case DICTIONARY_ELEMENTS: { + SeededNumberDictionary* element_dictionary = copy->element_dictionary(); + int capacity = element_dictionary->Capacity(); + for (int i = 0; i < capacity; i++) { + Object* k = element_dictionary->KeyAt(i); + if (element_dictionary->IsKey(k)) { + Object* value = element_dictionary->ValueAt(i); + if (value->IsJSObject()) { + JSObject* js_object = JSObject::cast(value); + { MaybeObject* maybe_result = js_object->DeepCopy(isolate); + if (!maybe_result->ToObject(&result)) return maybe_result; + } + element_dictionary->ValueAtPut(i, result); + } + } + } + break; + } + case NON_STRICT_ARGUMENTS_ELEMENTS: + UNIMPLEMENTED(); + break; + case EXTERNAL_PIXEL_ELEMENTS: + case EXTERNAL_BYTE_ELEMENTS: + case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: + case EXTERNAL_SHORT_ELEMENTS: + case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: + case EXTERNAL_INT_ELEMENTS: + case EXTERNAL_UNSIGNED_INT_ELEMENTS: + case EXTERNAL_FLOAT_ELEMENTS: + case EXTERNAL_DOUBLE_ELEMENTS: + case FAST_DOUBLE_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: + // No contained objects, nothing to do. + break; + } + return copy; +} + + // Tests for the fast common case for property enumeration: // - This object and all prototypes has an enum cache (which means that // it is no proxy, has no interceptors and needs no access checks). @@ -7626,33 +7793,45 @@ bool String::SlowAsArrayIndex(uint32_t* index) { } -String* SeqString::Truncate(int new_length) { - Heap* heap = GetHeap(); - if (new_length <= 0) return heap->empty_string(); - - int string_size, allocated_string_size; - int old_length = length(); - if (old_length <= new_length) return this; +Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) { + int new_size, old_size; + int old_length = string->length(); + if (old_length <= new_length) return string; - if (IsSeqOneByteString()) { - allocated_string_size = SeqOneByteString::SizeFor(old_length); - string_size = SeqOneByteString::SizeFor(new_length); + if (string->IsSeqOneByteString()) { + old_size = SeqOneByteString::SizeFor(old_length); + new_size = SeqOneByteString::SizeFor(new_length); } else { - allocated_string_size = SeqTwoByteString::SizeFor(old_length); - string_size = SeqTwoByteString::SizeFor(new_length); + ASSERT(string->IsSeqTwoByteString()); + old_size = SeqTwoByteString::SizeFor(old_length); + new_size = SeqTwoByteString::SizeFor(new_length); } - int delta = allocated_string_size - string_size; - set_length(new_length); + int delta = old_size - new_size; + string->set_length(new_length); - // String sizes are pointer size aligned, so that we can use filler objects - // that are a multiple of pointer size. - Address end_of_string = address() + string_size; - heap->CreateFillerObjectAt(end_of_string, delta); - if (Marking::IsBlack(Marking::MarkBitFrom(this))) { - MemoryChunk::IncrementLiveBytesFromMutator(address(), -delta); + Address start_of_string = string->address(); + ASSERT_OBJECT_ALIGNED(start_of_string); + ASSERT_OBJECT_ALIGNED(start_of_string + new_size); + + Heap* heap = string->GetHeap(); + NewSpace* newspace = heap->new_space(); + if (newspace->Contains(start_of_string) && + newspace->top() == start_of_string + old_size) { + // Last allocated object in new space. Simply lower allocation top. + *(newspace->allocation_top_address()) = start_of_string + new_size; + } else { + // Sizes are pointer size aligned, so that we can use filler objects + // that are a multiple of pointer size. + heap->CreateFillerObjectAt(start_of_string + new_size, delta); } - return this; + if (Marking::IsBlack(Marking::MarkBitFrom(start_of_string))) { + MemoryChunk::IncrementLiveBytesFromMutator(start_of_string, -delta); + } + + + if (new_length == 0) return heap->isolate()->factory()->empty_string(); + return string; } @@ -8813,19 +8992,13 @@ void Code::CopyFrom(const CodeDesc& desc) { ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT); // copy code - CHECK(IsCode()); - CHECK(relocation_info()->IsByteArray()); - CHECK(reinterpret_cast<intptr_t>(instruction_start()) == - reinterpret_cast<intptr_t>(this) + Code::kHeaderSize - kHeapObjectTag); - memmove(instruction_start(), desc.buffer, desc.instr_size); + CopyBytes(instruction_start(), desc.buffer, + static_cast<size_t>(desc.instr_size)); // copy reloc info - // TODO(mstarzinger): Remove once we found the bug. - CHECK(IsCode()); - CHECK(relocation_info()->IsByteArray()); - memmove(relocation_start(), - desc.buffer + desc.buffer_size - desc.reloc_size, - desc.reloc_size); + CopyBytes(relocation_start(), + desc.buffer + desc.buffer_size - desc.reloc_size, + static_cast<size_t>(desc.reloc_size)); // unbox handles and relocate intptr_t delta = instruction_start() - desc.buffer; @@ -9758,9 +9931,14 @@ MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) { void Map::ZapTransitions() { TransitionArray* transition_array = transitions(); - MemsetPointer(transition_array->data_start(), - GetHeap()->the_hole_value(), - transition_array->length()); + // TODO(mstarzinger): Temporarily use a slower version instead of the faster + // MemsetPointer to investigate a crasher. Switch back to MemsetPointer. + Object** data = transition_array->data_start(); + Object* the_hole = GetHeap()->the_hole_value(); + int length = transition_array->length(); + for (int i = 0; i < length; i++) { + data[i] = the_hole; + } } @@ -11593,18 +11771,22 @@ void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) { // Fill in the names of local properties into the supplied storage. The main // purpose of this function is to provide reflection information for the object // mirrors. -void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) { - ASSERT(storage->length() >= (NumberOfLocalProperties() - index)); +void JSObject::GetLocalPropertyNames( + FixedArray* storage, int index, PropertyAttributes filter) { + ASSERT(storage->length() >= (NumberOfLocalProperties(filter) - index)); if (HasFastProperties()) { int real_size = map()->NumberOfOwnDescriptors(); DescriptorArray* descs = map()->instance_descriptors(); - ASSERT(storage->length() >= index + real_size); for (int i = 0; i < real_size; i++) { - storage->set(index + i, descs->GetKey(i)); + if ((descs->GetDetails(i).attributes() & filter) == 0 && + ((filter & SYMBOLIC) == 0 || !descs->GetKey(i)->IsSymbol())) { + storage->set(index++, descs->GetKey(i)); + } } } else { property_dictionary()->CopyKeysTo(storage, index, + filter, NameDictionary::UNSORTED); } } @@ -12355,6 +12537,7 @@ template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Shrink( template void Dictionary<NameDictionaryShape, Name*>::CopyKeysTo( FixedArray*, int, + PropertyAttributes, Dictionary<NameDictionaryShape, Name*>::SortMode); template int @@ -13597,6 +13780,7 @@ template<typename Shape, typename Key> void Dictionary<Shape, Key>::CopyKeysTo( FixedArray* storage, int index, + PropertyAttributes filter, typename Dictionary<Shape, Key>::SortMode sort_mode) { ASSERT(storage->length() >= NumberOfElementsFilterAttributes( static_cast<PropertyAttributes>(NONE))); @@ -13606,7 +13790,8 @@ void Dictionary<Shape, Key>::CopyKeysTo( if (HashTable<Shape, Key>::IsKey(k)) { PropertyDetails details = DetailsAt(i); if (details.IsDeleted()) continue; - storage->set(index++, k); + PropertyAttributes attr = details.attributes(); + if ((attr & filter) == 0) storage->set(index++, k); } } if (sort_mode == Dictionary<Shape, Key>::SORTED) { diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 933a07599..37be25f88 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -56,6 +56,7 @@ // - JSReceiver (suitable for property access) // - JSObject // - JSArray +// - JSArrayBuffer // - JSSet // - JSMap // - JSWeakMap @@ -399,6 +400,7 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; V(JS_BUILTINS_OBJECT_TYPE) \ V(JS_GLOBAL_PROXY_TYPE) \ V(JS_ARRAY_TYPE) \ + V(JS_ARRAY_BUFFER_TYPE) \ V(JS_PROXY_TYPE) \ V(JS_WEAK_MAP_TYPE) \ V(JS_REGEXP_TYPE) \ @@ -729,6 +731,7 @@ enum InstanceType { JS_BUILTINS_OBJECT_TYPE, JS_GLOBAL_PROXY_TYPE, JS_ARRAY_TYPE, + JS_ARRAY_BUFFER_TYPE, JS_SET_TYPE, JS_MAP_TYPE, JS_WEAK_MAP_TYPE, @@ -974,6 +977,7 @@ class MaybeObject BASE_EMBEDDED { V(Foreign) \ V(Boolean) \ V(JSArray) \ + V(JSArrayBuffer) \ V(JSProxy) \ V(JSFunctionProxy) \ V(JSSet) \ @@ -1102,9 +1106,6 @@ class Object : public MaybeObject { // Return the object's prototype (might be Heap::null_value()). Object* GetPrototype(Isolate* isolate); - // Return the prototype, or the method holder for a value-like object. - Object* GetDelegate(Isolate* isolate); - // Returns the permanent hash code associated with this object depending on // the actual object type. Might return a failure in case no hash was // created yet or GC was caused by creation. @@ -2060,7 +2061,8 @@ class JSObject: public JSReceiver { int NumberOfLocalProperties(PropertyAttributes filter = NONE); // Fill in details for properties into storage starting at the specified // index. - void GetLocalPropertyNames(FixedArray* storage, int index); + void GetLocalPropertyNames( + FixedArray* storage, int index, PropertyAttributes filter = NONE); // Returns the number of properties on this object filtering out properties // with the specified attributes (ignoring interceptors). @@ -2216,6 +2218,8 @@ class JSObject: public JSReceiver { static Handle<Object> PreventExtensions(Handle<JSObject> object); MUST_USE_RESULT MaybeObject* PreventExtensions(); + // Copy object + MUST_USE_RESULT MaybeObject* DeepCopy(Isolate* isolate); // Dispatched behavior. void JSObjectShortPrint(StringStream* accumulator); @@ -3258,7 +3262,10 @@ class Dictionary: public HashTable<Shape, Key> { PropertyAttributes filter, SortMode sort_mode); // Fill in details for properties into storage. - void CopyKeysTo(FixedArray* storage, int index, SortMode sort_mode); + void CopyKeysTo(FixedArray* storage, + int index, + PropertyAttributes filter, + SortMode sort_mode); // Accessors for next enumeration index. void SetNextEnumerationIndex(int index) { @@ -4347,6 +4354,11 @@ class Code: public HeapObject { NONEXISTENT }; + enum StubHolder { + OWN_STUB, + PROTOTYPE_STUB + }; + enum { NUMBER_OF_KINDS = LAST_IC_KIND + 1 }; @@ -4542,6 +4554,8 @@ class Code: public HeapObject { class ExtraICStateKeyedAccessStoreMode: public BitField<KeyedAccessStoreMode, 1, 4> {}; // NOLINT + class ExtraICStateStubHolder: public BitField<StubHolder, 0, 1> {}; + static inline StrictModeFlag GetStrictMode(ExtraICState extra_ic_state) { return ExtraICStateStrictMode::decode(extra_ic_state); } @@ -4558,6 +4572,10 @@ class Code: public HeapObject { ExtraICStateStrictMode::encode(strict_mode); } + static inline ExtraICState ComputeExtraICState(StubHolder stub_holder) { + return ExtraICStateStubHolder::encode(stub_holder); + } + // Flags operations. static inline Flags ComputeFlags( Kind kind, @@ -5943,6 +5961,9 @@ class SharedFunctionInfo: public HeapObject { // Indicates that code for this function cannot be cached. DECL_BOOLEAN_ACCESSORS(dont_cache) + // Indicates that this function is a generator. + DECL_BOOLEAN_ACCESSORS(is_generator) + // Indicates whether or not the code in the shared function support // deoptimization. inline bool has_deoptimization_support(); @@ -6169,6 +6190,7 @@ class SharedFunctionInfo: public HeapObject { kDontOptimize, kDontInline, kDontCache, + kIsGenerator, kCompilerHintsCount // Pseudo entry }; @@ -7401,6 +7423,9 @@ class Name: public HeapObject { // ES6 symbols. class Symbol: public Name { public: + // [name]: the print name of a symbol, or undefined if none. + DECL_ACCESSORS(name, Object) + // Casting. static inline Symbol* cast(Object* obj); @@ -7409,7 +7434,11 @@ class Symbol: public Name { DECLARE_VERIFIER(Symbol) // Layout description. - static const int kSize = Name::kSize; + static const int kNameOffset = Name::kSize; + static const int kSize = kNameOffset + kPointerSize; + + typedef FixedBodyDescriptor<kNameOffset, kNameOffset + kPointerSize, kSize> + BodyDescriptor; private: DISALLOW_IMPLICIT_CONSTRUCTORS(Symbol); @@ -7754,8 +7783,8 @@ class SeqString: public String { // Truncate the string in-place if possible and return the result. // In case of new_length == 0, the empty string is returned without // truncating the original string. - MUST_USE_RESULT String* Truncate(int new_length); - + MUST_USE_RESULT static Handle<String> Truncate(Handle<SeqString> string, + int new_length); private: DISALLOW_IMPLICIT_CONSTRUCTORS(SeqString); }; @@ -8464,6 +8493,30 @@ class JSWeakMap: public JSObject { }; +class JSArrayBuffer: public JSObject { + public: + // [backing_store]: backing memory for thsi array + DECL_ACCESSORS(backing_store, void) + + // [byte_length]: length in bytes + DECL_ACCESSORS(byte_length, Object) + + // Casting. + static inline JSArrayBuffer* cast(Object* obj); + + // Dispatched behavior. + DECLARE_PRINTER(JSArrayBuffer) + DECLARE_VERIFIER(JSArrayBuffer) + + static const int kBackingStoreOffset = JSObject::kHeaderSize; + static const int kByteLengthOffset = kBackingStoreOffset + kPointerSize; + static const int kSize = kByteLengthOffset + kPointerSize; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBuffer); +}; + + // Foreign describes objects pointing from JavaScript to C structures. // Since they cannot contain references to JS HeapObjects they can be // placed in old_data_space. diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc index cdc0adb56..d1228d2f7 100644 --- a/deps/v8/src/parser.cc +++ b/deps/v8/src/parser.cc @@ -486,10 +486,12 @@ class Parser::BlockState BASE_EMBEDDED { Parser::FunctionState::FunctionState(Parser* parser, Scope* scope, + bool is_generator, Isolate* isolate) : next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize), next_handler_index_(0), expected_property_count_(0), + is_generator_(is_generator), only_simple_this_property_assignments_(false), this_property_assignments_(isolate->factory()->empty_fixed_array()), parser_(parser), @@ -642,7 +644,10 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, } ParsingModeScope parsing_mode(this, mode); - FunctionState function_state(this, scope, isolate()); // Enters 'scope'. + bool is_generator = false; + // Enters 'scope'. + FunctionState function_state(this, scope, is_generator, isolate()); + top_scope_->SetLanguageMode(info->language_mode()); ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone()); bool ok = true; @@ -680,7 +685,8 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::kGlobalOrEval, - FunctionLiteral::kNotParenthesized); + FunctionLiteral::kNotParenthesized, + FunctionLiteral::kNotGenerator); result->set_ast_properties(factory()->visitor()->ast_properties()); } else if (stack_overflow_) { isolate()->StackOverflow(); @@ -754,7 +760,8 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source, scope = Scope::DeserializeScopeChain(info()->closure()->context(), scope, zone()); } - FunctionState function_state(this, scope, isolate()); + bool is_generator = false; // Top scope is not a generator. + FunctionState function_state(this, scope, is_generator, isolate()); ASSERT(scope->language_mode() != STRICT_MODE || !info()->is_classic_mode()); ASSERT(scope->language_mode() != EXTENDED_MODE || info()->is_extended_mode()); @@ -768,6 +775,7 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source, bool ok = true; result = ParseFunctionLiteral(name, false, // Strict mode name already checked. + shared_info->is_generator(), RelocInfo::kNoPosition, type, &ok); @@ -1132,6 +1140,7 @@ Statement* Parser::ParseModuleElement(ZoneStringList* labels, // ModuleDeclaration // ImportDeclaration // ExportDeclaration + // GeneratorDeclaration switch (peek()) { case Token::FUNCTION: @@ -1430,6 +1439,7 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { // 'export' Identifier (',' Identifier)* ';' // 'export' VariableDeclaration // 'export' FunctionDeclaration + // 'export' GeneratorDeclaration // 'export' ModuleDeclaration // // TODO(ES6): implement structuring ExportSpecifiers @@ -1509,6 +1519,7 @@ Statement* Parser::ParseBlockElement(ZoneStringList* labels, // BlockElement (aka SourceElement): // LetDeclaration // ConstDeclaration + // GeneratorDeclaration switch (peek()) { case Token::FUNCTION: @@ -1628,6 +1639,10 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { // FunctionDeclaration // Common language extension is to allow function declaration in place // of any statement. This language extension is disabled in strict mode. + // + // In Harmony mode, this case also handles the extension: + // Statement: + // GeneratorDeclaration if (!top_scope_->is_classic_mode()) { ReportMessageAt(scanner().peek_location(), "strict_function", Vector<const char*>::empty()); @@ -1890,13 +1905,18 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) { Statement* Parser::ParseFunctionDeclaration(ZoneStringList* names, bool* ok) { // FunctionDeclaration :: // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}' + // GeneratorDeclaration :: + // 'function' '*' Identifier '(' FormalParameterListopt ')' + // '{' FunctionBody '}' Expect(Token::FUNCTION, CHECK_OK); int function_token_position = scanner().location().beg_pos; + bool is_generator = FLAG_harmony_generators && Check(Token::MUL); bool is_strict_reserved = false; Handle<String> name = ParseIdentifierOrStrictReservedWord( &is_strict_reserved, CHECK_OK); FunctionLiteral* fun = ParseFunctionLiteral(name, is_strict_reserved, + is_generator, function_token_position, FunctionLiteral::DECLARATION, CHECK_OK); @@ -3004,8 +3024,13 @@ Expression* Parser::ParseExpression(bool accept_IN, bool* ok) { Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) { // AssignmentExpression :: // ConditionalExpression + // YieldExpression // LeftHandSideExpression AssignmentOperator AssignmentExpression + if (peek() == Token::YIELD && is_generator()) { + return ParseYieldExpression(ok); + } + if (fni_ != NULL) fni_->Enter(); Expression* expression = ParseConditionalExpression(accept_IN, CHECK_OK); @@ -3074,6 +3099,17 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) { } +Expression* Parser::ParseYieldExpression(bool* ok) { + // YieldExpression :: + // 'yield' '*'? AssignmentExpression + int position = scanner().peek_location().beg_pos; + Expect(Token::YIELD, CHECK_OK); + bool is_yield_star = Check(Token::MUL); + Expression* expression = ParseAssignmentExpression(false, CHECK_OK); + return factory()->NewYield(expression, is_yield_star, position); +} + + // Precedence = 3 Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) { // ConditionalExpression :: @@ -3450,6 +3486,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack, if (peek() == Token::FUNCTION) { Expect(Token::FUNCTION, CHECK_OK); int function_token_position = scanner().location().beg_pos; + bool is_generator = FLAG_harmony_generators && Check(Token::MUL); Handle<String> name; bool is_strict_reserved_name = false; if (peek_any_identifier()) { @@ -3461,6 +3498,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack, : FunctionLiteral::NAMED_EXPRESSION; result = ParseFunctionLiteral(name, is_strict_reserved_name, + is_generator, function_token_position, type, CHECK_OK); @@ -3544,6 +3582,7 @@ void Parser::ReportUnexpectedToken(Token::Value token) { case Token::FUTURE_RESERVED_WORD: return ReportMessage("unexpected_reserved", Vector<const char*>::empty()); + case Token::YIELD: case Token::FUTURE_STRICT_RESERVED_WORD: return ReportMessage(top_scope_->is_classic_mode() ? "unexpected_token_identifier" : @@ -3604,6 +3643,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) { break; case Token::IDENTIFIER: + case Token::YIELD: case Token::FUTURE_STRICT_RESERVED_WORD: { Handle<String> name = ParseIdentifier(CHECK_OK); if (fni_ != NULL) fni_->PushVariableName(name); @@ -4009,6 +4049,7 @@ ObjectLiteral::Property* Parser::ParseObjectLiteralGetSet(bool is_getter, FunctionLiteral* value = ParseFunctionLiteral(name, false, // reserved words are allowed here + false, // not a generator RelocInfo::kNoPosition, FunctionLiteral::ANONYMOUS_EXPRESSION, CHECK_OK); @@ -4310,6 +4351,7 @@ class SingletonLogger : public ParserRecorder { FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, bool name_is_strict_reserved, + bool is_generator, int function_token_position, FunctionLiteral::Type type, bool* ok) { @@ -4344,9 +4386,12 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_ ? FunctionLiteral::kIsParenthesized : FunctionLiteral::kNotParenthesized; + FunctionLiteral::IsGeneratorFlag generator = is_generator + ? FunctionLiteral::kIsGenerator + : FunctionLiteral::kNotGenerator; AstProperties ast_properties; // Parse function body. - { FunctionState function_state(this, scope, isolate()); + { FunctionState function_state(this, scope, is_generator, isolate()); top_scope_->SetScopeName(function_name); // FormalParameterList :: @@ -4584,7 +4629,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, duplicate_parameters, type, FunctionLiteral::kIsFunction, - parenthesized); + parenthesized, + generator); function_literal->set_function_token_position(function_token_position); function_literal->set_ast_properties(&ast_properties); @@ -4606,10 +4652,12 @@ preparser::PreParser::PreParseResult Parser::LazyParseFunctionLiteral( stack_limit, do_allow_lazy, allow_natives_syntax_, - allow_modules_); + allow_modules_, + FLAG_harmony_generators); } preparser::PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(top_scope_->language_mode(), + is_generator(), logger); return result; } @@ -4672,7 +4720,8 @@ bool Parser::peek_any_identifier() { Token::Value next = peek(); return next == Token::IDENTIFIER || next == Token::FUTURE_RESERVED_WORD || - next == Token::FUTURE_STRICT_RESERVED_WORD; + next == Token::FUTURE_STRICT_RESERVED_WORD || + next == Token::YIELD; } @@ -4744,13 +4793,17 @@ Literal* Parser::GetLiteralTheHole() { // Parses an identifier that is valid for the current scope, in particular it // fails on strict mode future reserved keywords in a strict scope. Handle<String> Parser::ParseIdentifier(bool* ok) { - if (!top_scope_->is_classic_mode()) { - Expect(Token::IDENTIFIER, ok); - } else if (!Check(Token::IDENTIFIER)) { - Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok); + Token::Value next = Next(); + if (next == Token::IDENTIFIER || + (top_scope_->is_classic_mode() && + (next == Token::FUTURE_STRICT_RESERVED_WORD || + (next == Token::YIELD && !is_generator())))) { + return GetSymbol(ok); + } else { + ReportUnexpectedToken(next); + *ok = false; + return Handle<String>(); } - if (!*ok) return Handle<String>(); - return GetSymbol(ok); } @@ -4758,12 +4811,17 @@ Handle<String> Parser::ParseIdentifier(bool* ok) { // whether it is strict mode future reserved. Handle<String> Parser::ParseIdentifierOrStrictReservedWord( bool* is_strict_reserved, bool* ok) { - *is_strict_reserved = false; - if (!Check(Token::IDENTIFIER)) { - Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok); + Token::Value next = Next(); + if (next == Token::IDENTIFIER) { + *is_strict_reserved = false; + } else if (next == Token::FUTURE_STRICT_RESERVED_WORD || + (next == Token::YIELD && !is_generator())) { *is_strict_reserved = true; + } else { + ReportUnexpectedToken(next); + *ok = false; + return Handle<String>(); } - if (!*ok) return Handle<String>(); return GetSymbol(ok); } @@ -5875,6 +5933,9 @@ ScriptDataImpl* ParserApi::PreParse(Utf16CharacterStream* source, if (FLAG_lazy && (extension == NULL)) { flags |= kAllowLazy; } + if (FLAG_harmony_generators) { + flags |= kAllowGenerators; + } CompleteParserRecorder recorder; return DoPreParse(source, flags, &recorder); } diff --git a/deps/v8/src/parser.h b/deps/v8/src/parser.h index 6dcf7f129..fc4aba2b9 100644 --- a/deps/v8/src/parser.h +++ b/deps/v8/src/parser.h @@ -474,6 +474,7 @@ class Parser { public: FunctionState(Parser* parser, Scope* scope, + bool is_generator, Isolate* isolate); ~FunctionState(); @@ -504,6 +505,8 @@ class Parser { void AddProperty() { expected_property_count_++; } int expected_property_count() { return expected_property_count_; } + bool is_generator() const { return is_generator_; } + AstNodeFactory<AstConstructionVisitor>* factory() { return &factory_; } private: @@ -518,6 +521,9 @@ class Parser { // Properties count estimation. int expected_property_count_; + // Indicates that this function is a generator. + bool is_generator_; + // Keeps track of assignments to properties of this. Used for // optimizing constructors. bool only_simple_this_property_assignments_; @@ -631,6 +637,7 @@ class Parser { Expression* ParseExpression(bool accept_IN, bool* ok); Expression* ParseAssignmentExpression(bool accept_IN, bool* ok); + Expression* ParseYieldExpression(bool* ok); Expression* ParseConditionalExpression(bool accept_IN, bool* ok); Expression* ParseBinaryExpression(int prec, bool accept_IN, bool* ok); Expression* ParseUnaryExpression(bool* ok); @@ -674,6 +681,7 @@ class Parser { ZoneList<Expression*>* ParseArguments(bool* ok); FunctionLiteral* ParseFunctionLiteral(Handle<String> var_name, bool name_is_reserved, + bool is_generator, int function_token_position, FunctionLiteral::Type type, bool* ok); @@ -703,6 +711,8 @@ class Parser { return scanner().Next(); } + bool is_generator() const { return current_function_state_->is_generator(); } + bool peek_any_identifier(); INLINE(void Consume(Token::Value token)); diff --git a/deps/v8/src/platform-linux.cc b/deps/v8/src/platform-linux.cc index d21f160b4..1f9cde151 100644 --- a/deps/v8/src/platform-linux.cc +++ b/deps/v8/src/platform-linux.cc @@ -111,8 +111,10 @@ static bool CPUInfoContainsString(const char * search_string) { FILE* f = NULL; const char* what = search_string; - if (NULL == (f = fopen(file_name, "r"))) + if (NULL == (f = fopen(file_name, "r"))) { + OS::PrintError("Failed to open /proc/cpuinfo\n"); return false; + } int k; while (EOF != (k = fgetc(f))) { diff --git a/deps/v8/src/platform-posix.cc b/deps/v8/src/platform-posix.cc index 69d39112a..0016d59d3 100644 --- a/deps/v8/src/platform-posix.cc +++ b/deps/v8/src/platform-posix.cc @@ -109,26 +109,11 @@ void* OS::GetRandomMmapAddr() { raw_addr &= V8_UINT64_C(0x3ffffffff000); #else uint32_t raw_addr = V8::RandomPrivate(isolate); - - raw_addr &= 0x3ffff000; - -# ifdef __sun - // For our Solaris/illumos mmap hint, we pick a random address in the bottom - // half of the top half of the address space (that is, the third quarter). - // Because we do not MAP_FIXED, this will be treated only as a hint -- the - // system will not fail to mmap() because something else happens to already - // be mapped at our random address. We deliberately set the hint high enough - // to get well above the system's break (that is, the heap); Solaris and - // illumos will try the hint and if that fails allocate as if there were - // no hint at all. The high hint prevents the break from getting hemmed in - // at low values, ceding half of the address space to the system heap. - raw_addr += 0x80000000; -# else // The range 0x20000000 - 0x60000000 is relatively unpopulated across a // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos // 10.6 and 10.7. + raw_addr &= 0x3ffff000; raw_addr += 0x20000000; -# endif #endif return reinterpret_cast<void*>(raw_addr); } diff --git a/deps/v8/src/platform.h b/deps/v8/src/platform.h index 56ac61dc7..f2a228c92 100644 --- a/deps/v8/src/platform.h +++ b/deps/v8/src/platform.h @@ -348,7 +348,7 @@ class OS { static void MemCopy(void* dest, const void* src, size_t size) { memcpy(dest, src, size); } - static const int kMinComplexMemCopy = 256; + static const int kMinComplexMemCopy = 16 * kPointerSize; #endif // V8_TARGET_ARCH_IA32 static int GetCurrentProcessId(); diff --git a/deps/v8/src/preparser.cc b/deps/v8/src/preparser.cc index c461d8a4b..c61a08db9 100644 --- a/deps/v8/src/preparser.cc +++ b/deps/v8/src/preparser.cc @@ -53,12 +53,13 @@ int isfinite(double value); namespace preparser { PreParser::PreParseResult PreParser::PreParseLazyFunction( - i::LanguageMode mode, i::ParserRecorder* log) { + i::LanguageMode mode, bool is_generator, i::ParserRecorder* log) { log_ = log; // Lazy functions always have trivial outer scopes (no with/catch scopes). Scope top_scope(&scope_, kTopLevelScope); set_language_mode(mode); Scope function_scope(&scope_, kFunctionScope); + function_scope.set_is_generator(is_generator); ASSERT_EQ(i::Token::LBRACE, scanner_->current_token()); bool ok = true; int start_position = scanner_->peek_location().beg_pos; @@ -154,6 +155,7 @@ PreParser::Statement PreParser::ParseSourceElement(bool* ok) { // SourceElement: // LetDeclaration // ConstDeclaration + // GeneratorDeclaration switch (peek()) { case i::Token::FUNCTION: @@ -294,19 +296,23 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) { PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) { // FunctionDeclaration :: // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}' + // GeneratorDeclaration :: + // 'function' '*' Identifier '(' FormalParameterListopt ')' + // '{' FunctionBody '}' Expect(i::Token::FUNCTION, CHECK_OK); + bool is_generator = allow_generators_ && Check(i::Token::MUL); Identifier identifier = ParseIdentifier(CHECK_OK); i::Scanner::Location location = scanner_->location(); - Expression function_value = ParseFunctionLiteral(CHECK_OK); + Expression function_value = ParseFunctionLiteral(is_generator, CHECK_OK); if (function_value.IsStrictFunction() && !identifier.IsValidStrictVariable()) { // Strict mode violation, using either reserved word or eval/arguments // as name of strict function. const char* type = "strict_function_name"; - if (identifier.IsFutureStrictReserved()) { + if (identifier.IsFutureStrictReserved() || identifier.IsYield()) { type = "strict_reserved_word"; } ReportMessageAt(location, type, NULL); @@ -475,7 +481,9 @@ PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(bool* ok) { Expression expr = ParseExpression(true, CHECK_OK); if (expr.IsRawIdentifier()) { ASSERT(!expr.AsIdentifier().IsFutureReserved()); - ASSERT(is_classic_mode() || !expr.AsIdentifier().IsFutureStrictReserved()); + ASSERT(is_classic_mode() || + (!expr.AsIdentifier().IsFutureStrictReserved() && + !expr.AsIdentifier().IsYield())); if (peek() == i::Token::COLON) { Consume(i::Token::COLON); return ParseStatement(ok); @@ -810,8 +818,13 @@ PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN, bool* ok) { // AssignmentExpression :: // ConditionalExpression + // YieldExpression // LeftHandSideExpression AssignmentOperator AssignmentExpression + if (scope_->is_generator() && peek() == i::Token::YIELD) { + return ParseYieldExpression(ok); + } + i::Scanner::Location before = scanner_->peek_location(); Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK); @@ -842,6 +855,19 @@ PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN, // Precedence = 3 +PreParser::Expression PreParser::ParseYieldExpression(bool* ok) { + // YieldExpression :: + // 'yield' '*'? AssignmentExpression + Consume(i::Token::YIELD); + Check(i::Token::MUL); + + ParseAssignmentExpression(false, CHECK_OK); + + return Expression::Default(); +} + + +// Precedence = 3 PreParser::Expression PreParser::ParseConditionalExpression(bool accept_IN, bool* ok) { // ConditionalExpression :: @@ -1034,11 +1060,13 @@ PreParser::Expression PreParser::ParseMemberWithNewPrefixesExpression( Expression result = Expression::Default(); if (peek() == i::Token::FUNCTION) { Consume(i::Token::FUNCTION); + + bool is_generator = allow_generators_ && Check(i::Token::MUL); Identifier identifier = Identifier::Default(); if (peek_any_identifier()) { identifier = ParseIdentifier(CHECK_OK); } - result = ParseFunctionLiteral(CHECK_OK); + result = ParseFunctionLiteral(is_generator, CHECK_OK); if (result.IsStrictFunction() && !identifier.IsValidStrictVariable()) { StrictModeIdentifierViolation(scanner_->location(), "strict_function_name", @@ -1112,6 +1140,7 @@ PreParser::Expression PreParser::ParsePrimaryExpression(bool* ok) { case i::Token::FUTURE_RESERVED_WORD: case i::Token::FUTURE_STRICT_RESERVED_WORD: + case i::Token::YIELD: case i::Token::IDENTIFIER: { Identifier id = ParseIdentifier(CHECK_OK); result = Expression::FromIdentifier(id); @@ -1257,7 +1286,7 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) { } PropertyType type = is_getter ? kGetterProperty : kSetterProperty; CheckDuplicate(&duplicate_finder, name, type, CHECK_OK); - ParseFunctionLiteral(CHECK_OK); + ParseFunctionLiteral(false, CHECK_OK); if (peek() != i::Token::RBRACE) { Expect(i::Token::COMMA, CHECK_OK); } @@ -1344,7 +1373,8 @@ PreParser::Arguments PreParser::ParseArguments(bool* ok) { } -PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) { +PreParser::Expression PreParser::ParseFunctionLiteral(bool is_generator, + bool* ok) { // Function :: // '(' FormalParameterList? ')' '{' FunctionBody '}' @@ -1352,6 +1382,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) { ScopeType outer_scope_type = scope_->type(); bool inside_with = scope_->IsInsideWith(); Scope function_scope(&scope_, kFunctionScope); + function_scope.set_is_generator(is_generator); // FormalParameterList :: // '(' (Identifier)*[','] ')' Expect(i::Token::LPAREN, CHECK_OK); @@ -1497,6 +1528,8 @@ PreParser::Identifier PreParser::GetIdentifierSymbol() { } else if (scanner_->current_token() == i::Token::FUTURE_STRICT_RESERVED_WORD) { return Identifier::FutureStrictReserved(); + } else if (scanner_->current_token() == i::Token::YIELD) { + return Identifier::Yield(); } if (scanner_->is_literal_ascii()) { // Detect strict-mode poison words. @@ -1523,6 +1556,14 @@ PreParser::Identifier PreParser::ParseIdentifier(bool* ok) { *ok = false; return GetIdentifierSymbol(); } + case i::Token::YIELD: + if (scope_->is_generator()) { + // 'yield' in a generator is only valid as part of a YieldExpression. + ReportMessageAt(scanner_->location(), "unexpected_token", "yield"); + *ok = false; + return Identifier::Yield(); + } + // FALLTHROUGH case i::Token::FUTURE_STRICT_RESERVED_WORD: if (!is_classic_mode()) { i::Scanner::Location location = scanner_->location(); @@ -1580,7 +1621,7 @@ void PreParser::StrictModeIdentifierViolation(i::Scanner::Location location, const char* type = eval_args_type; if (identifier.IsFutureReserved()) { type = "reserved_word"; - } else if (identifier.IsFutureStrictReserved()) { + } else if (identifier.IsFutureStrictReserved() || identifier.IsYield()) { type = "strict_reserved_word"; } if (!is_classic_mode()) { @@ -1634,7 +1675,8 @@ bool PreParser::peek_any_identifier() { i::Token::Value next = peek(); return next == i::Token::IDENTIFIER || next == i::Token::FUTURE_RESERVED_WORD || - next == i::Token::FUTURE_STRICT_RESERVED_WORD; + next == i::Token::FUTURE_STRICT_RESERVED_WORD || + next == i::Token::YIELD; } diff --git a/deps/v8/src/preparser.h b/deps/v8/src/preparser.h index ad52d74bb..ce9aa7546 100644 --- a/deps/v8/src/preparser.h +++ b/deps/v8/src/preparser.h @@ -104,6 +104,11 @@ class DuplicateFinder { }; +#ifdef WIN32 +#undef Yield +#endif + + class PreParser { public: enum PreParseResult { @@ -117,7 +122,8 @@ class PreParser { uintptr_t stack_limit, bool allow_lazy, bool allow_natives_syntax, - bool allow_modules) + bool allow_modules, + bool allow_generators) : scanner_(scanner), log_(log), scope_(NULL), @@ -128,6 +134,7 @@ class PreParser { allow_lazy_(allow_lazy), allow_modules_(allow_modules), allow_natives_syntax_(allow_natives_syntax), + allow_generators_(allow_generators), parenthesized_function_(false), harmony_scoping_(scanner->HarmonyScoping()) { } @@ -144,19 +151,22 @@ class PreParser { bool allow_lazy = (flags & i::kAllowLazy) != 0; bool allow_natives_syntax = (flags & i::kAllowNativesSyntax) != 0; bool allow_modules = (flags & i::kAllowModules) != 0; + bool allow_generators = (flags & i::kAllowGenerators) != 0; return PreParser(scanner, log, stack_limit, allow_lazy, - allow_natives_syntax, allow_modules).PreParse(); + allow_natives_syntax, allow_modules, + allow_generators).PreParse(); } // Parses a single function literal, from the opening parentheses before // parameters to the closing brace after the body. // Returns a FunctionEntry describing the body of the function in enough // detail that it can be lazily compiled. - // The scanner is expected to have matched the "function" keyword and - // parameters, and have consumed the initial '{'. + // The scanner is expected to have matched the "function" or "function*" + // keyword and parameters, and have consumed the initial '{'. // At return, unless an error occurred, the scanner is positioned before the // the final '}'. PreParseResult PreParseLazyFunction(i::LanguageMode mode, + bool is_generator, i::ParserRecorder* log); private: @@ -240,9 +250,13 @@ class PreParser { static Identifier FutureStrictReserved() { return Identifier(kFutureStrictReservedIdentifier); } + static Identifier Yield() { + return Identifier(kYieldIdentifier); + } bool IsEval() { return type_ == kEvalIdentifier; } bool IsArguments() { return type_ == kArgumentsIdentifier; } bool IsEvalOrArguments() { return type_ >= kEvalIdentifier; } + bool IsYield() { return type_ == kYieldIdentifier; } bool IsFutureReserved() { return type_ == kFutureReservedIdentifier; } bool IsFutureStrictReserved() { return type_ == kFutureStrictReservedIdentifier; @@ -254,6 +268,7 @@ class PreParser { kUnknownIdentifier, kFutureReservedIdentifier, kFutureStrictReservedIdentifier, + kYieldIdentifier, kEvalIdentifier, kArgumentsIdentifier }; @@ -347,7 +362,7 @@ class PreParser { // Identifiers and string literals can be parenthesized. // They no longer work as labels or directive prologues, // but are still recognized in other contexts. - return Expression(code_ | kParentesizedExpressionFlag); + return Expression(code_ | kParenthesizedExpressionFlag); } // For other types of expressions, it's not important to remember // the parentheses. @@ -373,7 +388,8 @@ class PreParser { kUseStrictString = kStringLiteralFlag | 8, kStringLiteralMask = kUseStrictString, - kParentesizedExpressionFlag = 4, // Only if identifier or string literal. + // Only if identifier or string literal. + kParenthesizedExpressionFlag = 4, // Below here applies if neither identifier nor string literal. kThisExpression = 4, @@ -451,7 +467,8 @@ class PreParser { expected_properties_(0), with_nesting_count_(0), language_mode_( - (prev_ != NULL) ? prev_->language_mode() : i::CLASSIC_MODE) { + (prev_ != NULL) ? prev_->language_mode() : i::CLASSIC_MODE), + is_generator_(false) { *variable = this; } ~Scope() { *variable_ = prev_; } @@ -461,6 +478,8 @@ class PreParser { int expected_properties() { return expected_properties_; } int materialized_literal_count() { return materialized_literal_count_; } bool IsInsideWith() { return with_nesting_count_ != 0; } + bool is_generator() { return is_generator_; } + void set_is_generator(bool is_generator) { is_generator_ = is_generator; } bool is_classic_mode() { return language_mode_ == i::CLASSIC_MODE; } @@ -492,6 +511,7 @@ class PreParser { int expected_properties_; int with_nesting_count_; i::LanguageMode language_mode_; + bool is_generator_; }; // Preparse the program. Only called in PreParseProgram after creating @@ -557,6 +577,7 @@ class PreParser { Expression ParseExpression(bool accept_IN, bool* ok); Expression ParseAssignmentExpression(bool accept_IN, bool* ok); + Expression ParseYieldExpression(bool* ok); Expression ParseConditionalExpression(bool accept_IN, bool* ok); Expression ParseBinaryExpression(int prec, bool accept_IN, bool* ok); Expression ParseUnaryExpression(bool* ok); @@ -572,7 +593,7 @@ class PreParser { Expression ParseV8Intrinsic(bool* ok); Arguments ParseArguments(bool* ok); - Expression ParseFunctionLiteral(bool* ok); + Expression ParseFunctionLiteral(bool is_generator, bool* ok); void ParseLazyFunctionLiteralBody(bool* ok); Identifier ParseIdentifier(bool* ok); @@ -664,6 +685,7 @@ class PreParser { bool allow_lazy_; bool allow_modules_; bool allow_natives_syntax_; + bool allow_generators_; bool parenthesized_function_; bool harmony_scoping_; }; diff --git a/deps/v8/src/prettyprinter.cc b/deps/v8/src/prettyprinter.cc index df6183a36..50a71ced3 100644 --- a/deps/v8/src/prettyprinter.cc +++ b/deps/v8/src/prettyprinter.cc @@ -353,6 +353,12 @@ void PrettyPrinter::VisitAssignment(Assignment* node) { } +void PrettyPrinter::VisitYield(Yield* node) { + Print("yield "); + Visit(node->expression()); +} + + void PrettyPrinter::VisitThrow(Throw* node) { Print("throw "); Visit(node->exception()); @@ -1059,6 +1065,11 @@ void AstPrinter::VisitAssignment(Assignment* node) { } +void AstPrinter::VisitYield(Yield* node) { + PrintIndentedVisit("YIELD", node->expression()); +} + + void AstPrinter::VisitThrow(Throw* node) { PrintIndentedVisit("THROW", node->exception()); } diff --git a/deps/v8/src/property.h b/deps/v8/src/property.h index 546967ac4..bbba8aea6 100644 --- a/deps/v8/src/property.h +++ b/deps/v8/src/property.h @@ -362,12 +362,16 @@ class LookupResult BASE_EMBEDDED { return NULL; } - Map* GetTransitionTarget() { + Map* GetTransitionTarget(Map* map) { ASSERT(IsTransition()); - TransitionArray* transitions = holder()->map()->transitions(); + TransitionArray* transitions = map->transitions(); return transitions->GetTarget(number_); } + Map* GetTransitionTarget() { + return GetTransitionTarget(holder()->map()); + } + PropertyDetails GetTransitionDetails(Map* map) { ASSERT(IsTransition()); TransitionArray* transitions = map->transitions(); diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index e220d6bed..78efc8dbe 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -26,6 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <stdlib.h> +#include <limits> #include "v8.h" @@ -138,148 +139,6 @@ namespace internal { static_cast<LanguageMode>(args.smi_at(index)); -MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate, - JSObject* boilerplate) { - StackLimitCheck check(isolate); - if (check.HasOverflowed()) return isolate->StackOverflow(); - - Heap* heap = isolate->heap(); - Object* result; - { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - JSObject* copy = JSObject::cast(result); - - // Deep copy local properties. - if (copy->HasFastProperties()) { - FixedArray* properties = copy->properties(); - for (int i = 0; i < properties->length(); i++) { - Object* value = properties->get(i); - if (value->IsJSObject()) { - JSObject* js_object = JSObject::cast(value); - { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - properties->set(i, result); - } - } - int nof = copy->map()->inobject_properties(); - for (int i = 0; i < nof; i++) { - Object* value = copy->InObjectPropertyAt(i); - if (value->IsJSObject()) { - JSObject* js_object = JSObject::cast(value); - { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - copy->InObjectPropertyAtPut(i, result); - } - } - } else { - { MaybeObject* maybe_result = - heap->AllocateFixedArray(copy->NumberOfLocalProperties()); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - FixedArray* names = FixedArray::cast(result); - copy->GetLocalPropertyNames(names, 0); - for (int i = 0; i < names->length(); i++) { - ASSERT(names->get(i)->IsString()); - String* key_string = String::cast(names->get(i)); - PropertyAttributes attributes = - copy->GetLocalPropertyAttribute(key_string); - // Only deep copy fields from the object literal expression. - // In particular, don't try to copy the length attribute of - // an array. - if (attributes != NONE) continue; - Object* value = - copy->GetProperty(key_string, &attributes)->ToObjectUnchecked(); - if (value->IsJSObject()) { - JSObject* js_object = JSObject::cast(value); - { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - { MaybeObject* maybe_result = - // Creating object copy for literals. No strict mode needed. - copy->SetProperty(key_string, result, NONE, kNonStrictMode); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - } - } - } - - // Deep copy local elements. - // Pixel elements cannot be created using an object literal. - ASSERT(!copy->HasExternalArrayElements()); - switch (copy->GetElementsKind()) { - case FAST_SMI_ELEMENTS: - case FAST_ELEMENTS: - case FAST_HOLEY_SMI_ELEMENTS: - case FAST_HOLEY_ELEMENTS: { - FixedArray* elements = FixedArray::cast(copy->elements()); - if (elements->map() == heap->fixed_cow_array_map()) { - isolate->counters()->cow_arrays_created_runtime()->Increment(); -#ifdef DEBUG - for (int i = 0; i < elements->length(); i++) { - ASSERT(!elements->get(i)->IsJSObject()); - } -#endif - } else { - for (int i = 0; i < elements->length(); i++) { - Object* value = elements->get(i); - ASSERT(value->IsSmi() || - value->IsTheHole() || - (IsFastObjectElementsKind(copy->GetElementsKind()))); - if (value->IsJSObject()) { - JSObject* js_object = JSObject::cast(value); - { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, - js_object); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - elements->set(i, result); - } - } - } - break; - } - case DICTIONARY_ELEMENTS: { - SeededNumberDictionary* element_dictionary = copy->element_dictionary(); - int capacity = element_dictionary->Capacity(); - for (int i = 0; i < capacity; i++) { - Object* k = element_dictionary->KeyAt(i); - if (element_dictionary->IsKey(k)) { - Object* value = element_dictionary->ValueAt(i); - if (value->IsJSObject()) { - JSObject* js_object = JSObject::cast(value); - { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, - js_object); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - element_dictionary->ValueAtPut(i, result); - } - } - } - break; - } - case NON_STRICT_ARGUMENTS_ELEMENTS: - UNIMPLEMENTED(); - break; - case EXTERNAL_PIXEL_ELEMENTS: - case EXTERNAL_BYTE_ELEMENTS: - case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - case EXTERNAL_SHORT_ELEMENTS: - case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - case EXTERNAL_INT_ELEMENTS: - case EXTERNAL_UNSIGNED_INT_ELEMENTS: - case EXTERNAL_FLOAT_ELEMENTS: - case EXTERNAL_DOUBLE_ELEMENTS: - case FAST_DOUBLE_ELEMENTS: - case FAST_HOLEY_DOUBLE_ELEMENTS: - // No contained objects, nothing to do. - break; - } - return copy; -} - - static Handle<Map> ComputeObjectLiteralMap( Handle<Context> context, Handle<FixedArray> constant_properties, @@ -598,7 +457,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) { // Update the functions literal and return the boilerplate. literals->set(literals_index, *boilerplate); } - return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate)); + return JSObject::cast(*boilerplate)->DeepCopy(isolate); } @@ -645,7 +504,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) { // Update the functions literal and return the boilerplate. literals->set(literals_index, *boilerplate); } - return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate)); + return JSObject::cast(*boilerplate)->DeepCopy(isolate); } @@ -683,9 +542,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) { RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateSymbol) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + Handle<Object> name(args[0], isolate); + RUNTIME_ASSERT(name->IsString() || name->IsUndefined()); + Symbol* symbol; + MaybeObject* maybe = isolate->heap()->AllocateSymbol(); + if (!maybe->To(&symbol)) return maybe; + if (name->IsString()) symbol->set_name(*name); + return symbol; +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolName) { NoHandleAllocation ha(isolate); - ASSERT(args.length() == 0); - return isolate->heap()->AllocateSymbol(); + ASSERT(args.length() == 1); + CONVERT_ARG_CHECKED(Symbol, symbol, 0); + return symbol->name(); } @@ -764,6 +637,125 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) { } +static size_t ArrayBufferAllocatedLength(Isolate* isolate, + JSArrayBuffer* buffer) { + NoHandleAllocation hc(isolate); + Object* byte_length = buffer->byte_length(); + if (byte_length->IsSmi()) { + return Smi::cast(byte_length)->value(); + } else { + double value = HeapNumber::cast(byte_length)->value(); + return static_cast<size_t>(value); + } +} + + +static void ArrayBufferWeakCallback(v8::Isolate* external_isolate, + Persistent<Value> object, + void* data) { + Isolate* isolate = reinterpret_cast<Isolate*>(external_isolate); + HandleScope scope(isolate); + Handle<Object> internal_object = Utils::OpenHandle(*object); + + size_t allocated_length = ArrayBufferAllocatedLength( + isolate, JSArrayBuffer::cast(*internal_object)); + isolate->heap()->AdjustAmountOfExternalAllocatedMemory( + -static_cast<intptr_t>(allocated_length)); + if (data != NULL) + free(data); + object.Dispose(external_isolate); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferInitialize) { + HandleScope scope(isolate); + ASSERT(args.length() == 2); + CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); + CONVERT_ARG_HANDLE_CHECKED(Object, byteLength, 1); + size_t allocated_length; + if (byteLength->IsSmi()) { + allocated_length = Smi::cast(*byteLength)->value(); + } else { + ASSERT(byteLength->IsHeapNumber()); + double value = HeapNumber::cast(*byteLength)->value(); + + ASSERT(value >= 0); + + if (value > std::numeric_limits<size_t>::max()) { + return isolate->Throw( + *isolate->factory()->NewRangeError("invalid_array_buffer_length", + HandleVector<Object>(NULL, 0))); + } + + allocated_length = static_cast<size_t>(value); + } + + void* data; + if (allocated_length != 0) { + data = malloc(allocated_length); + + if (data == NULL) { + return isolate->Throw(*isolate->factory()-> + NewRangeError("invalid_array_buffer_length", + HandleVector<Object>(NULL, 0))); + } + + memset(data, 0, allocated_length); + } else { + data = NULL; + } + holder->set_backing_store(data); + + Object* byte_length; + { + MaybeObject* maybe_byte_length = + isolate->heap()->NumberFromDouble( + static_cast<double>(allocated_length)); + if (!maybe_byte_length->ToObject(&byte_length)) return maybe_byte_length; + } + CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber()); + holder->set_byte_length(byte_length); + + v8::Isolate* external_isolate = reinterpret_cast<v8::Isolate*>(isolate); + v8::Handle<Object> external_holder(*holder); + Persistent<Object> weak_handle = Persistent<Object>::New( + external_isolate, external_holder); + weak_handle.MakeWeak(external_isolate, data, ArrayBufferWeakCallback); + weak_handle.MarkIndependent(external_isolate); + isolate->heap()->AdjustAmountOfExternalAllocatedMemory(allocated_length); + + return *holder; +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferGetByteLength) { + NoHandleAllocation ha(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0); + return holder->byte_length(); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) { + HandleScope scope(isolate); + ASSERT(args.length() == 3); + CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0); + CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1); + CONVERT_DOUBLE_ARG_CHECKED(first, 2); + size_t start = static_cast<size_t>(first); + size_t target_length = ArrayBufferAllocatedLength(isolate, *target); + + if (target_length == 0) + return isolate->heap()->undefined_value(); + + ASSERT(ArrayBufferAllocatedLength(isolate, *source) - target_length >= start); + uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store()); + uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store()); + CopyBytes(target_data, source_data + start, target_length); + return isolate->heap()->undefined_value(); +} + + RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -4731,11 +4723,13 @@ static int LocalPrototypeChainLength(JSObject* obj) { // args[0]: object RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) { HandleScope scope(isolate); - ASSERT(args.length() == 1); + ASSERT(args.length() == 2); if (!args[0]->IsJSObject()) { return isolate->heap()->undefined_value(); } CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); + CONVERT_BOOLEAN_ARG_CHECKED(include_symbols, 1); + PropertyAttributes filter = include_symbols ? NONE : SYMBOLIC; // Skip the global proxy as it has no properties and always delegates to the // real global object. @@ -4768,7 +4762,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) { return *isolate->factory()->NewJSArray(0); } int n; - n = jsproto->NumberOfLocalProperties(); + n = jsproto->NumberOfLocalProperties(filter); local_property_count[i] = n; total_property_count += n; if (i < length - 1) { @@ -4785,7 +4779,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) { int proto_with_hidden_properties = 0; int next_copy_index = 0; for (int i = 0; i < length; i++) { - jsproto->GetLocalPropertyNames(*names, next_copy_index); + jsproto->GetLocalPropertyNames(*names, next_copy_index, filter); next_copy_index += local_property_count[i]; if (jsproto->HasHiddenProperties()) { proto_with_hidden_properties++; @@ -4795,7 +4789,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) { } } - // Filter out name of hidden propeties object. + // Filter out name of hidden properties object. if (proto_with_hidden_properties > 0) { Handle<FixedArray> old_names = names; names = isolate->factory()->NewFixedArray( @@ -5035,6 +5029,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) { } ASSERT(heap_obj->IsUndefined()); return isolate->heap()->undefined_string(); + case SYMBOL_TYPE: + return isolate->heap()->symbol_string(); case JS_FUNCTION_TYPE: case JS_FUNCTION_PROXY_TYPE: return isolate->heap()->function_string(); @@ -5137,10 +5133,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewString) { RUNTIME_FUNCTION(MaybeObject*, Runtime_TruncateString) { - NoHandleAllocation ha(isolate); - CONVERT_ARG_CHECKED(SeqString, string, 0); + HandleScope scope(isolate); + CONVERT_ARG_HANDLE_CHECKED(SeqString, string, 0); CONVERT_SMI_ARG_CHECKED(new_length, 1); - return string->Truncate(new_length); + return *SeqString::Truncate(string, new_length); } @@ -5171,365 +5167,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) { } -static const unsigned int kQuoteTableLength = 128u; - -static const int kJsonQuotesCharactersPerEntry = 8; -static const char* const JsonQuotes = - "\\u0000 \\u0001 \\u0002 \\u0003 " - "\\u0004 \\u0005 \\u0006 \\u0007 " - "\\b \\t \\n \\u000b " - "\\f \\r \\u000e \\u000f " - "\\u0010 \\u0011 \\u0012 \\u0013 " - "\\u0014 \\u0015 \\u0016 \\u0017 " - "\\u0018 \\u0019 \\u001a \\u001b " - "\\u001c \\u001d \\u001e \\u001f " - " ! \\\" # " - "$ % & ' " - "( ) * + " - ", - . / " - "0 1 2 3 " - "4 5 6 7 " - "8 9 : ; " - "< = > ? " - "@ A B C " - "D E F G " - "H I J K " - "L M N O " - "P Q R S " - "T U V W " - "X Y Z [ " - "\\\\ ] ^ _ " - "` a b c " - "d e f g " - "h i j k " - "l m n o " - "p q r s " - "t u v w " - "x y z { " - "| } ~ \177 "; - - -// For a string that is less than 32k characters it should always be -// possible to allocate it in new space. -static const int kMaxGuaranteedNewSpaceString = 32 * 1024; - - -// Doing JSON quoting cannot make the string more than this many times larger. -static const int kJsonQuoteWorstCaseBlowup = 6; - -static const int kSpaceForQuotesAndComma = 3; -static const int kSpaceForBrackets = 2; - -// Covers the entire ASCII range (all other characters are unchanged by JSON -// quoting). -static const byte JsonQuoteLengths[kQuoteTableLength] = { - 6, 6, 6, 6, 6, 6, 6, 6, - 2, 2, 2, 6, 2, 2, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, - 1, 1, 2, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 2, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, -}; - - -template <typename StringType> -MaybeObject* AllocateRawString(Isolate* isolate, int length); - - -template <> -MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) { - return isolate->heap()->AllocateRawTwoByteString(length); -} - - -template <> -MaybeObject* AllocateRawString<SeqOneByteString>(Isolate* isolate, int length) { - return isolate->heap()->AllocateRawOneByteString(length); -} - - -template <typename Char, typename StringType, bool comma> -static MaybeObject* SlowQuoteJsonString(Isolate* isolate, - Vector<const Char> characters) { - int length = characters.length(); - const Char* read_cursor = characters.start(); - const Char* end = read_cursor + length; - const int kSpaceForQuotes = 2 + (comma ? 1 :0); - int quoted_length = kSpaceForQuotes; - while (read_cursor < end) { - Char c = *(read_cursor++); - if (static_cast<unsigned>(c) >= kQuoteTableLength) { - quoted_length++; - } else { - quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)]; - } - } - MaybeObject* new_alloc = AllocateRawString<StringType>(isolate, - quoted_length); - Object* new_object; - if (!new_alloc->ToObject(&new_object)) { - return new_alloc; - } - StringType* new_string = StringType::cast(new_object); - - Char* write_cursor = reinterpret_cast<Char*>( - new_string->address() + SeqString::kHeaderSize); - if (comma) *(write_cursor++) = ','; - *(write_cursor++) = '"'; - - read_cursor = characters.start(); - while (read_cursor < end) { - Char c = *(read_cursor++); - if (static_cast<unsigned>(c) >= kQuoteTableLength) { - *(write_cursor++) = c; - } else { - int len = JsonQuoteLengths[static_cast<unsigned>(c)]; - const char* replacement = JsonQuotes + - static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry; - for (int i = 0; i < len; i++) { - *write_cursor++ = *replacement++; - } - } - } - *(write_cursor++) = '"'; - return new_string; -} - - -template <typename SinkChar, typename SourceChar> -static inline SinkChar* WriteQuoteJsonString( - Isolate* isolate, - SinkChar* write_cursor, - Vector<const SourceChar> characters) { - // SinkChar is only char if SourceChar is guaranteed to be char. - ASSERT(sizeof(SinkChar) >= sizeof(SourceChar)); - const SourceChar* read_cursor = characters.start(); - const SourceChar* end = read_cursor + characters.length(); - *(write_cursor++) = '"'; - while (read_cursor < end) { - SourceChar c = *(read_cursor++); - if (static_cast<unsigned>(c) >= kQuoteTableLength) { - *(write_cursor++) = static_cast<SinkChar>(c); - } else { - int len = JsonQuoteLengths[static_cast<unsigned>(c)]; - const char* replacement = JsonQuotes + - static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry; - write_cursor[0] = replacement[0]; - if (len > 1) { - write_cursor[1] = replacement[1]; - if (len > 2) { - ASSERT(len == 6); - write_cursor[2] = replacement[2]; - write_cursor[3] = replacement[3]; - write_cursor[4] = replacement[4]; - write_cursor[5] = replacement[5]; - } - } - write_cursor += len; - } - } - *(write_cursor++) = '"'; - return write_cursor; -} - - -template <typename Char, typename StringType, bool comma> -static MaybeObject* QuoteJsonString(Isolate* isolate, - Vector<const Char> characters) { - int length = characters.length(); - isolate->counters()->quote_json_char_count()->Increment(length); - int worst_case_length = - length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma; - if (worst_case_length > kMaxGuaranteedNewSpaceString) { - return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters); - } - - MaybeObject* new_alloc = AllocateRawString<StringType>(isolate, - worst_case_length); - Object* new_object; - if (!new_alloc->ToObject(&new_object)) { - return new_alloc; - } - if (!isolate->heap()->new_space()->Contains(new_object)) { - // Even if our string is small enough to fit in new space we still have to - // handle it being allocated in old space as may happen in the third - // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in - // CEntryStub::GenerateCore. - return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters); - } - StringType* new_string = StringType::cast(new_object); - ASSERT(isolate->heap()->new_space()->Contains(new_string)); - - Char* write_cursor = reinterpret_cast<Char*>( - new_string->address() + SeqString::kHeaderSize); - if (comma) *(write_cursor++) = ','; - write_cursor = WriteQuoteJsonString<Char, Char>(isolate, - write_cursor, - characters); - int final_length = static_cast<int>( - write_cursor - reinterpret_cast<Char*>( - new_string->address() + SeqString::kHeaderSize)); - isolate->heap()->new_space()-> - template ShrinkStringAtAllocationBoundary<StringType>( - new_string, final_length); - return new_string; -} - - RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) { - NoHandleAllocation ha(isolate); - CONVERT_ARG_CHECKED(String, str, 0); - if (!str->IsFlat()) { - MaybeObject* try_flatten = str->TryFlatten(); - Object* flat; - if (!try_flatten->ToObject(&flat)) { - return try_flatten; - } - str = String::cast(flat); - ASSERT(str->IsFlat()); - } - String::FlatContent flat = str->GetFlatContent(); - ASSERT(flat.IsFlat()); - if (flat.IsTwoByte()) { - return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate, - flat.ToUC16Vector()); - } else { - return QuoteJsonString<uint8_t, SeqOneByteString, false>( - isolate, - flat.ToOneByteVector()); - } -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) { - NoHandleAllocation ha(isolate); - CONVERT_ARG_CHECKED(String, str, 0); - if (!str->IsFlat()) { - MaybeObject* try_flatten = str->TryFlatten(); - Object* flat; - if (!try_flatten->ToObject(&flat)) { - return try_flatten; - } - str = String::cast(flat); - ASSERT(str->IsFlat()); - } - String::FlatContent flat = str->GetFlatContent(); - if (flat.IsTwoByte()) { - return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate, - flat.ToUC16Vector()); - } else { - return QuoteJsonString<uint8_t, SeqOneByteString, true>( - isolate, - flat.ToOneByteVector()); - } -} - - -template <typename Char, typename StringType> -static MaybeObject* QuoteJsonStringArray(Isolate* isolate, - FixedArray* array, - int worst_case_length) { - int length = array->length(); - - MaybeObject* new_alloc = AllocateRawString<StringType>(isolate, - worst_case_length); - Object* new_object; - if (!new_alloc->ToObject(&new_object)) { - return new_alloc; - } - if (!isolate->heap()->new_space()->Contains(new_object)) { - // Even if our string is small enough to fit in new space we still have to - // handle it being allocated in old space as may happen in the third - // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in - // CEntryStub::GenerateCore. - return isolate->heap()->undefined_value(); - } - AssertNoAllocation no_gc; - StringType* new_string = StringType::cast(new_object); - ASSERT(isolate->heap()->new_space()->Contains(new_string)); - - Char* write_cursor = reinterpret_cast<Char*>( - new_string->address() + SeqString::kHeaderSize); - *(write_cursor++) = '['; - for (int i = 0; i < length; i++) { - if (i != 0) *(write_cursor++) = ','; - String* str = String::cast(array->get(i)); - String::FlatContent content = str->GetFlatContent(); - ASSERT(content.IsFlat()); - if (content.IsTwoByte()) { - write_cursor = WriteQuoteJsonString<Char, uc16>(isolate, - write_cursor, - content.ToUC16Vector()); - } else { - write_cursor = - WriteQuoteJsonString<Char, uint8_t>(isolate, - write_cursor, - content.ToOneByteVector()); - } - } - *(write_cursor++) = ']'; - - int final_length = static_cast<int>( - write_cursor - reinterpret_cast<Char*>( - new_string->address() + SeqString::kHeaderSize)); - isolate->heap()->new_space()-> - template ShrinkStringAtAllocationBoundary<StringType>( - new_string, final_length); - return new_string; -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) { - NoHandleAllocation ha(isolate); + HandleScope scope(isolate); + CONVERT_ARG_HANDLE_CHECKED(String, string, 0); ASSERT(args.length() == 1); - CONVERT_ARG_CHECKED(JSArray, array, 0); - - if (!array->HasFastObjectElements()) { - return isolate->heap()->undefined_value(); - } - FixedArray* elements = FixedArray::cast(array->elements()); - int n = elements->length(); - bool ascii = true; - int total_length = 0; - - for (int i = 0; i < n; i++) { - Object* elt = elements->get(i); - if (!elt->IsString()) return isolate->heap()->undefined_value(); - String* element = String::cast(elt); - if (!element->IsFlat()) return isolate->heap()->undefined_value(); - total_length += element->length(); - if (ascii && element->IsTwoByteRepresentation()) { - ascii = false; - } - } - - int worst_case_length = - kSpaceForBrackets + n * kSpaceForQuotesAndComma - + total_length * kJsonQuoteWorstCaseBlowup; - - if (worst_case_length > kMaxGuaranteedNewSpaceString) { - return isolate->heap()->undefined_value(); - } - - if (ascii) { - return QuoteJsonStringArray<char, SeqOneByteString>(isolate, - elements, - worst_case_length); - } else { - return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate, - elements, - worst_case_length); - } + return BasicJsonStringifier::StringifyString(isolate, string); } @@ -6134,6 +5776,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) { } +// ES6 draft 9.1.11 +RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPositiveInteger) { + NoHandleAllocation ha(isolate); + ASSERT(args.length() == 1); + + CONVERT_DOUBLE_ARG_CHECKED(number, 0); + + // We do not include 0 so that we don't have to treat +0 / -0 cases. + if (number > 0 && number <= Smi::kMaxValue) { + return Smi::FromInt(static_cast<int>(number)); + } + if (number <= 0) { + return Smi::FromInt(0); + } + return isolate->heap()->NumberFromDouble(DoubleToInteger(number)); +} + + RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) { NoHandleAllocation ha(isolate); ASSERT(args.length() == 1); @@ -9015,7 +8675,7 @@ static ObjectPair CompileGlobalEval(Isolate* isolate, // and return the compiled function bound in the local context. Handle<SharedFunctionInfo> shared = Compiler::CompileEval( source, - Handle<Context>(isolate->context()), + context, context->IsNativeContext(), language_mode, NO_PARSE_RESTRICTION, @@ -9085,8 +8745,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) { RUNTIME_ASSERT(IsAligned(size, kPointerSize)); RUNTIME_ASSERT(size > 0); Heap* heap = isolate->heap(); - const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4; - RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC); + RUNTIME_ASSERT(size <= heap->MaxNewSpaceAllocationSize()); Object* allocation; { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size); if (maybe_allocation->ToObject(&allocation)) { @@ -9896,9 +9555,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) { // Returns an array that tells you where in the [0, length) interval an array -// might have elements. Can either return keys (positive integers) or -// intervals (pair of a negative integer (-start-1) followed by a -// positive (length)) or undefined values. +// might have elements. Can either return an array of keys (positive integers +// or undefined) or a number representing the positive length of an interval +// starting at index 0. // Intervals can span over some keys that are not in the object. RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) { HandleScope scope(isolate); @@ -9906,37 +9565,34 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) { CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0); CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]); if (array->elements()->IsDictionary()) { - // Create an array and get all the keys into it, then remove all the - // keys that are not integers in the range 0 to length-1. - bool threw = false; - Handle<FixedArray> keys = - GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw); - if (threw) return Failure::Exception(); - - int keys_length = keys->length(); - for (int i = 0; i < keys_length; i++) { - Object* key = keys->get(i); - uint32_t index = 0; - if (!key->ToArrayIndex(&index) || index >= length) { - // Zap invalid keys. - keys->set_undefined(i); + Handle<FixedArray> keys = isolate->factory()->empty_fixed_array(); + for (Handle<Object> p = array; + !p->IsNull(); + p = Handle<Object>(p->GetPrototype(isolate), isolate)) { + if (p->IsJSProxy() || JSObject::cast(*p)->HasIndexedInterceptor()) { + // Bail out if we find a proxy or interceptor, likely not worth + // collecting keys in that case. + return *isolate->factory()->NewNumberFromUint(length); } + Handle<JSObject> current = Handle<JSObject>::cast(p); + Handle<FixedArray> current_keys = + isolate->factory()->NewFixedArray( + current->NumberOfLocalElements(NONE)); + current->GetLocalElementKeys(*current_keys, NONE); + keys = UnionOfKeys(keys, current_keys); + } + // Erase any keys >= length. + // TODO(adamk): Remove this step when the contract of %GetArrayKeys + // is changed to let this happen on the JS side. + for (int i = 0; i < keys->length(); i++) { + if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i); } return *isolate->factory()->NewJSArrayWithElements(keys); } else { ASSERT(array->HasFastSmiOrObjectElements() || array->HasFastDoubleElements()); - Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2); - // -1 means start of array. - single_interval->set(0, Smi::FromInt(-1)); - FixedArrayBase* elements = FixedArrayBase::cast(array->elements()); - uint32_t actual_length = - static_cast<uint32_t>(elements->length()); - uint32_t min_length = actual_length < length ? actual_length : length; - Handle<Object> length_object = - isolate->factory()->NewNumber(static_cast<double>(min_length)); - single_interval->set(1, *length_object); - return *isolate->factory()->NewJSArrayWithElements(single_interval); + uint32_t actual_length = static_cast<uint32_t>(array->elements()->length()); + return *isolate->factory()->NewNumberFromUint(Min(actual_length, length)); } } @@ -11811,6 +11467,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) { } +static bool IsBlockOrCatchOrWithScope(ScopeIterator::ScopeType type) { + return type == ScopeIterator::ScopeTypeBlock || + type == ScopeIterator::ScopeTypeCatch || + type == ScopeIterator::ScopeTypeWith; +} + + // Creates a copy of the with context chain. The copy of the context chain is // is linked to the function context supplied. static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate, @@ -11825,8 +11488,7 @@ static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate, ScopeIterator it(isolate, frame, inlined_jsframe_index); if (it.Failed()) return Handle<Context>::null(); - for (; it.Type() != ScopeIterator::ScopeTypeGlobal && - it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) { + for ( ; IsBlockOrCatchOrWithScope(it.Type()); it.Next()) { ASSERT(!it.Done()); scope_chain.Add(it.CurrentScopeInfo()); context_chain.Add(it.CurrentContext()); @@ -11842,6 +11504,7 @@ static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate, ASSERT(!(scope_info->HasContext() & current.is_null())); if (scope_info->Type() == CATCH_SCOPE) { + ASSERT(current->IsCatchContext()); Handle<String> name(String::cast(current->extension())); Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX), isolate); @@ -11852,6 +11515,7 @@ static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate, thrown_object); } else if (scope_info->Type() == BLOCK_SCOPE) { // Materialize the contents of the block scope into a JSObject. + ASSERT(current->IsBlockContext()); Handle<JSObject> block_scope_object = MaterializeBlockScope(isolate, current); CHECK(!block_scope_object.is_null()); @@ -11904,37 +11568,65 @@ static Handle<Object> GetArgumentsObject(Isolate* isolate, } } - Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction())); - int length = frame_inspector->GetParametersCount(); - Handle<JSObject> arguments = - isolate->factory()->NewArgumentsObject(function, length); - Handle<FixedArray> array = isolate->factory()->NewFixedArray(length); + // FunctionGetArguments can't return a non-Object. + return Handle<JSObject>(JSObject::cast( + Accessors::FunctionGetArguments(frame_inspector->GetFunction(), + NULL)->ToObjectUnchecked()), isolate); +} - AssertNoAllocation no_gc; - WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc); - for (int i = 0; i < length; i++) { - array->set(i, frame_inspector->GetParameter(i), mode); + +// Compile and evaluate source for the given context. +static MaybeObject* DebugEvaluate(Isolate* isolate, + Handle<Context> context, + Handle<Object> context_extension, + Handle<Object> receiver, + Handle<String> source) { + if (context_extension->IsJSObject()) { + Handle<JSObject> extension = Handle<JSObject>::cast(context_extension); + Handle<JSFunction> closure(context->closure(), isolate); + context = isolate->factory()->NewWithContext(closure, context, extension); } - arguments->set_elements(*array); - return arguments; -} + Handle<SharedFunctionInfo> shared = Compiler::CompileEval( + source, + context, + context->IsNativeContext(), + CLASSIC_MODE, + NO_PARSE_RESTRICTION, + RelocInfo::kNoPosition); + if (shared.is_null()) return Failure::Exception(); -static const char kSourceStr[] = - "(function(arguments,__source__){return eval(__source__);})"; + Handle<JSFunction> eval_fun = + isolate->factory()->NewFunctionFromSharedFunctionInfo( + shared, context, NOT_TENURED); + bool pending_exception; + Handle<Object> result = Execution::Call( + eval_fun, receiver, 0, NULL, &pending_exception); + + if (pending_exception) return Failure::Exception(); + + // Skip the global proxy as it has no properties and always delegates to the + // real global object. + if (result->IsJSGlobalProxy()) { + result = Handle<JSObject>(JSObject::cast(result->GetPrototype(isolate))); + } + + // Clear the oneshot breakpoints so that the debugger does not step further. + isolate->debug()->ClearStepping(); + return *result; +} // Evaluate a piece of JavaScript in the context of a stack frame for -// debugging. This is accomplished by creating a new context which in its -// extension part has all the parameters and locals of the function on the -// stack frame. A function which calls eval with the code to evaluate is then -// compiled in this context and called in this context. As this context -// replaces the context of the function on the stack frame a new (empty) -// function is created as well to be used as the closure for the context. -// This function and the context acts as replacements for the function on the -// stack frame presenting the same view of the values of parameters and -// local variables as if the piece of JavaScript was evaluated at the point -// where the function on the stack frame is currently stopped. +// debugging. This is done by creating a new context which in its extension +// part has all the parameters and locals of the function on the stack frame +// as well as a materialized arguments object. As this context replaces +// the context of the function on the stack frame a new (empty) function +// is created as well to be used as the closure for the context. +// This closure as replacements for the one on the stack frame presenting +// the same view of the values of parameters and local variables as if the +// piece of JavaScript was evaluated at the point where the function on the +// stack frame is currently stopped when we compile and run the (direct) eval. RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { HandleScope scope(isolate); @@ -11942,17 +11634,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { // evaluated. ASSERT(args.length() == 6); Object* check_result; - { MaybeObject* maybe_check_result = Runtime_CheckExecutionState( + { MaybeObject* maybe_result = Runtime_CheckExecutionState( RUNTIME_ARGUMENTS(isolate, args)); - if (!maybe_check_result->ToObject(&check_result)) { - return maybe_check_result; - } + if (!maybe_result->ToObject(&check_result)) return maybe_result; } CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); CONVERT_ARG_HANDLE_CHECKED(String, source, 3); CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4); - Handle<Object> additional_context(args[5], isolate); + Handle<Object> context_extension(args[5], isolate); // Handle the processing of break. DisableBreak disable_break_save(disable_break); @@ -11963,7 +11653,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { JavaScriptFrame* frame = it.frame(); FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); - Handle<ScopeInfo> scope_info(function->shared()->scope_info()); // Traverse the saved contexts chain to find the active context for the // selected frame. @@ -11988,28 +11677,42 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { ASSERT(go_between_scope_info->ContextLocalCount() == 0); #endif - // Materialize the content of the local scope into a JSObject. + // Materialize the content of the local scope including the arguments object. Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector( isolate, frame, &frame_inspector); RETURN_IF_EMPTY_HANDLE(isolate, local_scope); + // Do not materialize the arguments object for eval or top-level code. + if (function->shared()->is_function()) { + Handle<Context> frame_context(Context::cast(frame->context())); + Handle<Context> function_context; + Handle<ScopeInfo> scope_info(function->shared()->scope_info()); + if (scope_info->HasContext()) { + function_context = Handle<Context>(frame_context->declaration_context()); + } + Handle<Object> arguments = GetArgumentsObject(isolate, + frame, + &frame_inspector, + scope_info, + function_context); + SetProperty(isolate, + local_scope, + isolate->factory()->arguments_string(), + arguments, + ::NONE, + kNonStrictMode); + } + // Allocate a new context for the debug evaluation and set the extension // object build. - Handle<Context> context = - isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS, - go_between); + Handle<Context> context = isolate->factory()->NewFunctionContext( + Context::MIN_CONTEXT_SLOTS, go_between); // Use the materialized local scope in a with context. context = isolate->factory()->NewWithContext(go_between, context, local_scope); // Copy any with contexts present and chain them in front of this context. - Handle<Context> frame_context(Context::cast(frame->context())); - Handle<Context> function_context; - // Get the function's context if it has one. - if (scope_info->HasContext()) { - function_context = Handle<Context>(frame_context->declaration_context()); - } context = CopyNestedScopeContextChain(isolate, go_between, context, @@ -12022,79 +11725,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { return exception; } - if (additional_context->IsJSObject()) { - Handle<JSObject> extension = Handle<JSObject>::cast(additional_context); - context = - isolate->factory()->NewWithContext(go_between, context, extension); - } - - // Wrap the evaluation statement in a new function compiled in the newly - // created context. The function has one parameter which has to be called - // 'arguments'. This it to have access to what would have been 'arguments' in - // the function being debugged. - // function(arguments,__source__) {return eval(__source__);} - - Handle<String> function_source = - isolate->factory()->NewStringFromAscii( - Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1)); - - // Currently, the eval code will be executed in non-strict mode, - // even in the strict code context. - Handle<SharedFunctionInfo> shared = - Compiler::CompileEval(function_source, - context, - context->IsNativeContext(), - CLASSIC_MODE, - NO_PARSE_RESTRICTION, - RelocInfo::kNoPosition); - if (shared.is_null()) return Failure::Exception(); - Handle<JSFunction> compiled_function = - isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context); - - // Invoke the result of the compilation to get the evaluation function. - bool has_pending_exception; Handle<Object> receiver(frame->receiver(), isolate); - Handle<Object> evaluation_function = - Execution::Call(compiled_function, receiver, 0, NULL, - &has_pending_exception); - if (has_pending_exception) return Failure::Exception(); - - Handle<Object> arguments = GetArgumentsObject(isolate, - frame, - &frame_inspector, - scope_info, - function_context); - - // Check if eval is blocked in the context and temporarily allow it - // for debugger. - Handle<Context> native_context = Handle<Context>(context->native_context()); - bool eval_disabled = - native_context->allow_code_gen_from_strings()->IsFalse(); - if (eval_disabled) { - native_context->set_allow_code_gen_from_strings( - isolate->heap()->true_value()); - } - // Invoke the evaluation function and return the result. - Handle<Object> argv[] = { arguments, source }; - Handle<Object> result = - Execution::Call(Handle<JSFunction>::cast(evaluation_function), - receiver, - ARRAY_SIZE(argv), - argv, - &has_pending_exception); - if (eval_disabled) { - native_context->set_allow_code_gen_from_strings( - isolate->heap()->false_value()); - } - if (has_pending_exception) return Failure::Exception(); - - // Skip the global proxy as it has no properties and always delegates to the - // real global object. - if (result->IsJSGlobalProxy()) { - result = Handle<JSObject>(JSObject::cast(result->GetPrototype(isolate))); - } - - return *result; + return DebugEvaluate(isolate, context, context_extension, receiver, source); } @@ -12105,15 +11737,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) { // evaluated. ASSERT(args.length() == 4); Object* check_result; - { MaybeObject* maybe_check_result = Runtime_CheckExecutionState( + { MaybeObject* maybe_result = Runtime_CheckExecutionState( RUNTIME_ARGUMENTS(isolate, args)); - if (!maybe_check_result->ToObject(&check_result)) { - return maybe_check_result; - } + if (!maybe_result->ToObject(&check_result)) return maybe_result; } CONVERT_ARG_HANDLE_CHECKED(String, source, 1); CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2); - Handle<Object> additional_context(args[3], isolate); + Handle<Object> context_extension(args[3], isolate); // Handle the processing of break. DisableBreak disable_break_save(disable_break); @@ -12131,45 +11761,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) { // Get the native context now set to the top context from before the // debugger was invoked. Handle<Context> context = isolate->native_context(); - - bool is_global = true; - - if (additional_context->IsJSObject()) { - // Create a new with context with the additional context information between - // the context of the debugged function and the eval code to be executed. - context = isolate->factory()->NewWithContext( - Handle<JSFunction>(context->closure()), - context, - Handle<JSObject>::cast(additional_context)); - is_global = false; - } - - // Compile the source to be evaluated. - // Currently, the eval code will be executed in non-strict mode, - // even in the strict code context. - Handle<SharedFunctionInfo> shared = - Compiler::CompileEval(source, - context, - is_global, - CLASSIC_MODE, - NO_PARSE_RESTRICTION, - RelocInfo::kNoPosition); - if (shared.is_null()) return Failure::Exception(); - Handle<JSFunction> compiled_function = - Handle<JSFunction>( - isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, - context)); - - // Invoke the result of the compilation to get the evaluation function. - bool has_pending_exception; Handle<Object> receiver = isolate->global_object(); - Handle<Object> result = - Execution::Call(compiled_function, receiver, 0, NULL, - &has_pending_exception); - // Clear the oneshot breakpoints so that the debugger does not step further. - isolate->debug()->ClearStepping(); - if (has_pending_exception) return Failure::Exception(); - return *result; + return DebugEvaluate(isolate, context, context_extension, receiver, source); } @@ -13247,7 +12840,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_IsObserved) { CONVERT_ARG_CHECKED(JSReceiver, obj, 0); if (obj->IsJSGlobalProxy()) { Object* proto = obj->GetPrototype(); - if (obj->IsNull()) return isolate->heap()->false_value(); + if (proto->IsNull()) return isolate->heap()->false_value(); ASSERT(proto->IsJSGlobalObject()); obj = JSReceiver::cast(proto); } @@ -13262,7 +12855,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetIsObserved) { CONVERT_BOOLEAN_ARG_CHECKED(is_observed, 1); if (obj->IsJSGlobalProxy()) { Object* proto = obj->GetPrototype(); - if (obj->IsNull()) return isolate->heap()->undefined_value(); + if (proto->IsNull()) return isolate->heap()->undefined_value(); ASSERT(proto->IsJSGlobalObject()); obj = JSReceiver::cast(proto); } diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h index 2959fedc5..b16acd1d8 100644 --- a/deps/v8/src/runtime.h +++ b/deps/v8/src/runtime.h @@ -55,7 +55,7 @@ namespace internal { F(IsPropertyEnumerable, 2, 1) \ F(GetPropertyNames, 1, 1) \ F(GetPropertyNamesFast, 1, 1) \ - F(GetLocalPropertyNames, 1, 1) \ + F(GetLocalPropertyNames, 2, 1) \ F(GetLocalElementNames, 1, 1) \ F(GetInterceptorInfo, 1, 1) \ F(GetNamedInterceptorPropertyNames, 1, 1) \ @@ -129,6 +129,7 @@ namespace internal { F(NumberToString, 1, 1) \ F(NumberToStringSkipCache, 1, 1) \ F(NumberToInteger, 1, 1) \ + F(NumberToPositiveInteger, 1, 1) \ F(NumberToIntegerMapMinusZero, 1, 1) \ F(NumberToJSUint32, 1, 1) \ F(NumberToJSInt32, 1, 1) \ @@ -195,8 +196,6 @@ namespace internal { F(ParseJson, 1, 1) \ F(BasicJSONStringify, 1, 1) \ F(QuoteJSONString, 1, 1) \ - F(QuoteJSONStringComma, 1, 1) \ - F(QuoteJSONStringArray, 1, 1) \ \ /* Strings */ \ F(StringCharCodeAt, 2, 1) \ @@ -299,7 +298,8 @@ namespace internal { F(IsJSModule, 1, 1) \ \ /* Harmony symbols */ \ - F(CreateSymbol, 0, 1) \ + F(CreateSymbol, 1, 1) \ + F(SymbolName, 1, 1) \ \ /* Harmony proxies */ \ F(CreateJSProxy, 2, 1) \ @@ -341,6 +341,11 @@ namespace internal { F(ObservationWeakMapCreate, 0, 1) \ F(UnwrapGlobalProxy, 1, 1) \ \ + /* Harmony typed arrays */ \ + F(ArrayBufferInitialize, 2, 1)\ + F(ArrayBufferGetByteLength, 1, 1)\ + F(ArrayBufferSliceImpl, 3, 1) \ + \ /* Statements */ \ F(NewClosure, 3, 1) \ F(NewObject, 1, 1) \ @@ -514,7 +519,6 @@ namespace internal { #define INLINE_FUNCTION_LIST(F) \ F(IsSmi, 1, 1) \ F(IsNonNegativeSmi, 1, 1) \ - F(IsSymbol, 1, 1) \ F(IsArray, 1, 1) \ F(IsRegExp, 1, 1) \ F(IsConstructCall, 0, 1) \ diff --git a/deps/v8/src/runtime.js b/deps/v8/src/runtime.js index 09b39ffe1..22f888d81 100644 --- a/deps/v8/src/runtime.js +++ b/deps/v8/src/runtime.js @@ -69,16 +69,24 @@ function EQUALS(y) { } else if (IS_STRING(x)) { while (true) { if (IS_STRING(y)) return %StringEquals(x, y); + if (IS_SYMBOL(y)) return 1; // not equal if (IS_NUMBER(y)) return %NumberEquals(%ToNumber(x), y); if (IS_BOOLEAN(y)) return %NumberEquals(%ToNumber(x), %ToNumber(y)); if (IS_NULL_OR_UNDEFINED(y)) return 1; // not equal y = %ToPrimitive(y, NO_HINT); } + } else if (IS_SYMBOL(x)) { + while (true) { + if (IS_SYMBOL(y)) return %_ObjectEquals(x, y) ? 0 : 1; + if (!IS_SPEC_OBJECT(y)) return 1; // not equal + y = %ToPrimitive(y, NO_HINT); + } } else if (IS_BOOLEAN(x)) { if (IS_BOOLEAN(y)) return %_ObjectEquals(x, y) ? 0 : 1; if (IS_NULL_OR_UNDEFINED(y)) return 1; if (IS_NUMBER(y)) return %NumberEquals(%ToNumber(x), y); if (IS_STRING(y)) return %NumberEquals(%ToNumber(x), %ToNumber(y)); + if (IS_SYMBOL(y)) return 1; // not equal // y is object. x = %ToNumber(x); y = %ToPrimitive(y, NO_HINT); @@ -508,6 +516,7 @@ function ToPrimitive(x, hint) { if (IS_STRING(x)) return x; // Normal behavior. if (!IS_SPEC_OBJECT(x)) return x; + if (IS_SYMBOL_WRAPPER(x)) return %_ValueOf(x); if (hint == NO_HINT) hint = (IS_DATE(x)) ? STRING_HINT : NUMBER_HINT; return (hint == NUMBER_HINT) ? %DefaultNumber(x) : %DefaultString(x); } @@ -532,6 +541,7 @@ function ToNumber(x) { } if (IS_BOOLEAN(x)) return x ? 1 : 0; if (IS_UNDEFINED(x)) return $NaN; + if (IS_SYMBOL(x)) return $NaN; return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x)); } @@ -542,6 +552,7 @@ function NonNumberToNumber(x) { } if (IS_BOOLEAN(x)) return x ? 1 : 0; if (IS_UNDEFINED(x)) return $NaN; + if (IS_SYMBOL(x)) return $NaN; return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x)); } @@ -572,6 +583,7 @@ function ToName(x) { // ECMA-262, section 9.9, page 36. function ToObject(x) { if (IS_STRING(x)) return new $String(x); + if (IS_SYMBOL(x)) return new $Symbol(x); if (IS_NUMBER(x)) return new $Number(x); if (IS_BOOLEAN(x)) return new $Boolean(x); if (IS_NULL_OR_UNDEFINED(x) && !IS_UNDETECTABLE(x)) { diff --git a/deps/v8/src/scanner.cc b/deps/v8/src/scanner.cc index bd2db5818..ef2dc2c64 100755 --- a/deps/v8/src/scanner.cc +++ b/deps/v8/src/scanner.cc @@ -877,7 +877,7 @@ uc32 Scanner::ScanIdentifierUnicodeEscape() { KEYWORD("while", Token::WHILE) \ KEYWORD("with", Token::WITH) \ KEYWORD_GROUP('y') \ - KEYWORD("yield", Token::FUTURE_STRICT_RESERVED_WORD) + KEYWORD("yield", Token::YIELD) static Token::Value KeywordOrIdentifierToken(const char* input, diff --git a/deps/v8/src/scanner.h b/deps/v8/src/scanner.h index a454750de..dd1bfb8bf 100644 --- a/deps/v8/src/scanner.h +++ b/deps/v8/src/scanner.h @@ -53,7 +53,8 @@ enum ParsingFlags { kLanguageModeMask = 0x03, kAllowLazy = 0x04, kAllowNativesSyntax = 0x08, - kAllowModules = 0x10 + kAllowModules = 0x10, + kAllowGenerators = 0x20 }; STATIC_ASSERT((kLanguageModeMask & CLASSIC_MODE) == CLASSIC_MODE); diff --git a/deps/v8/src/spaces-inl.h b/deps/v8/src/spaces-inl.h index aeac570f4..77117b8a4 100644 --- a/deps/v8/src/spaces-inl.h +++ b/deps/v8/src/spaces-inl.h @@ -351,23 +351,6 @@ intptr_t LargeObjectSpace::Available() { } -template <typename StringType> -void NewSpace::ShrinkStringAtAllocationBoundary(String* string, int length) { - ASSERT(length <= string->length()); - ASSERT(string->IsSeqString()); - ASSERT(string->address() + StringType::SizeFor(string->length()) == - allocation_info_.top); - Address old_top = allocation_info_.top; - allocation_info_.top = - string->address() + StringType::SizeFor(length); - string->set_length(length); - if (Marking::IsBlack(Marking::MarkBitFrom(string))) { - int delta = static_cast<int>(old_top - allocation_info_.top); - MemoryChunk::IncrementLiveBytesFromMutator(string->address(), -delta); - } -} - - bool FreeListNode::IsFreeListNode(HeapObject* object) { Map* map = object->map(); Heap* heap = object->GetHeap(); diff --git a/deps/v8/src/spaces.cc b/deps/v8/src/spaces.cc index 2952fd52c..f8e6a1e87 100644 --- a/deps/v8/src/spaces.cc +++ b/deps/v8/src/spaces.cc @@ -1030,10 +1030,10 @@ intptr_t PagedSpace::SizeOfFirstPage() { size = 16 * kPointerSize * KB; break; case CODE_SPACE: - if (kPointerSize == 8) { - // On x64 we allocate code pages in a special way (from the reserved - // 2Byte area). That part of the code is not yet upgraded to handle - // small pages. + if (heap()->isolate()->code_range()->exists()) { + // When code range exists, code pages are allocated in a special way + // (from the reserved code range). That part of the code is not yet + // upgraded to handle small pages. size = AreaSize(); } else { size = 384 * KB; diff --git a/deps/v8/src/spaces.h b/deps/v8/src/spaces.h index 39c19a4e3..65eefd015 100644 --- a/deps/v8/src/spaces.h +++ b/deps/v8/src/spaces.h @@ -2419,11 +2419,6 @@ class NewSpace : public Space { virtual bool ReserveSpace(int bytes); - // Resizes a sequential string which must be the most recent thing that was - // allocated in new space. - template <typename StringType> - inline void ShrinkStringAtAllocationBoundary(String* string, int len); - #ifdef VERIFY_HEAP // Verify the active semispace. virtual void Verify(); diff --git a/deps/v8/src/stub-cache.cc b/deps/v8/src/stub-cache.cc index a0d98e27d..553c6f509 100644 --- a/deps/v8/src/stub-cache.cc +++ b/deps/v8/src/stub-cache.cc @@ -123,10 +123,13 @@ Handle<Code> StubCache::FindIC(Handle<Name> name, Handle<Code> StubCache::FindHandler(Handle<Name> name, + Handle<JSObject> receiver, Handle<JSObject> stub_holder, Code::Kind kind, - Code::StubType type, - Code::ExtraICState extra_ic_state) { + Code::StubType type) { + Code::ExtraICState extra_ic_state = Code::ComputeExtraICState( + receiver.is_identical_to(stub_holder) ? Code::OWN_STUB + : Code::PROTOTYPE_STUB); ASSERT(type != Code::NORMAL); Code::Flags flags = Code::ComputeMonomorphicFlags( Code::STUB, extra_ic_state, type, kind); @@ -194,7 +197,7 @@ Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name, // Compile the stub that is either shared for all names or // name specific if there are global objects involved. Handle<Code> handler = FindHandler( - cache_name, receiver, Code::LOAD_IC, Code::NONEXISTENT); + cache_name, receiver, receiver, Code::LOAD_IC, Code::NONEXISTENT); if (!handler.is_null()) return handler; LoadStubCompiler compiler(isolate_); @@ -218,7 +221,7 @@ Handle<Code> StubCache::ComputeLoadField(Handle<Name> name, Handle<JSObject> stub_holder = StubHolder(receiver, holder); Handle<Code> stub = FindHandler( - name, stub_holder, Code::LOAD_IC, Code::FIELD); + name, receiver, stub_holder, Code::LOAD_IC, Code::FIELD); if (!stub.is_null()) return stub; LoadStubCompiler compiler(isolate_); @@ -237,7 +240,7 @@ Handle<Code> StubCache::ComputeLoadCallback( ASSERT(v8::ToCData<Address>(callback->getter()) != 0); Handle<JSObject> stub_holder = StubHolder(receiver, holder); Handle<Code> stub = FindHandler( - name, stub_holder, Code::LOAD_IC, Code::CALLBACKS); + name, receiver, stub_holder, Code::LOAD_IC, Code::CALLBACKS); if (!stub.is_null()) return stub; LoadStubCompiler compiler(isolate_); @@ -254,7 +257,7 @@ Handle<Code> StubCache::ComputeLoadViaGetter(Handle<Name> name, Handle<JSFunction> getter) { Handle<JSObject> stub_holder = StubHolder(receiver, holder); Handle<Code> stub = FindHandler( - name, stub_holder, Code::LOAD_IC, Code::CALLBACKS); + name, receiver, stub_holder, Code::LOAD_IC, Code::CALLBACKS); if (!stub.is_null()) return stub; LoadStubCompiler compiler(isolate_); @@ -271,7 +274,7 @@ Handle<Code> StubCache::ComputeLoadConstant(Handle<Name> name, Handle<JSFunction> value) { Handle<JSObject> stub_holder = StubHolder(receiver, holder); Handle<Code> handler = FindHandler( - name, stub_holder, Code::LOAD_IC, Code::CONSTANT_FUNCTION); + name, receiver, stub_holder, Code::LOAD_IC, Code::CONSTANT_FUNCTION); if (!handler.is_null()) return handler; LoadStubCompiler compiler(isolate_); @@ -287,7 +290,7 @@ Handle<Code> StubCache::ComputeLoadInterceptor(Handle<Name> name, Handle<JSObject> holder) { Handle<JSObject> stub_holder = StubHolder(receiver, holder); Handle<Code> stub = FindHandler( - name, stub_holder, Code::LOAD_IC, Code::INTERCEPTOR); + name, receiver, stub_holder, Code::LOAD_IC, Code::INTERCEPTOR); if (!stub.is_null()) return stub; LoadStubCompiler compiler(isolate_); @@ -334,7 +337,7 @@ Handle<Code> StubCache::ComputeKeyedLoadField(Handle<Name> name, Handle<JSObject> stub_holder = StubHolder(receiver, holder); Handle<Code> stub = FindHandler( - name, stub_holder, Code::KEYED_LOAD_IC, Code::FIELD); + name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::FIELD); if (!stub.is_null()) return stub; KeyedLoadStubCompiler compiler(isolate_); @@ -351,7 +354,8 @@ Handle<Code> StubCache::ComputeKeyedLoadConstant(Handle<Name> name, Handle<JSFunction> value) { Handle<JSObject> stub_holder = StubHolder(receiver, holder); Handle<Code> handler = FindHandler( - name, stub_holder, Code::KEYED_LOAD_IC, Code::CONSTANT_FUNCTION); + name, receiver, stub_holder, Code::KEYED_LOAD_IC, + Code::CONSTANT_FUNCTION); if (!handler.is_null()) return handler; KeyedLoadStubCompiler compiler(isolate_); @@ -366,7 +370,7 @@ Handle<Code> StubCache::ComputeKeyedLoadInterceptor(Handle<Name> name, Handle<JSObject> holder) { Handle<JSObject> stub_holder = StubHolder(receiver, holder); Handle<Code> stub = FindHandler( - name, stub_holder, Code::KEYED_LOAD_IC, Code::INTERCEPTOR); + name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::INTERCEPTOR); if (!stub.is_null()) return stub; KeyedLoadStubCompiler compiler(isolate_); @@ -384,7 +388,7 @@ Handle<Code> StubCache::ComputeKeyedLoadCallback( Handle<ExecutableAccessorInfo> callback) { Handle<JSObject> stub_holder = StubHolder(receiver, holder); Handle<Code> stub = FindHandler( - name, stub_holder, Code::KEYED_LOAD_IC, Code::CALLBACKS); + name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::CALLBACKS); if (!stub.is_null()) return stub; KeyedLoadStubCompiler compiler(isolate_); @@ -397,7 +401,7 @@ Handle<Code> StubCache::ComputeKeyedLoadCallback( Handle<Code> StubCache::ComputeStoreField(Handle<Name> name, Handle<JSObject> receiver, - int field_index, + LookupResult* lookup, Handle<Map> transition, StrictModeFlag strict_mode) { Code::StubType type = @@ -409,7 +413,7 @@ Handle<Code> StubCache::ComputeStoreField(Handle<Name> name, StoreStubCompiler compiler(isolate_, strict_mode); Handle<Code> code = - compiler.CompileStoreField(receiver, field_index, transition, name); + compiler.CompileStoreField(receiver, lookup, transition, name); JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -441,7 +445,9 @@ Handle<Code> StubCache::ComputeKeyedStoreElement( Code::KEYED_STORE_IC, extra_state); ASSERT(store_mode == STANDARD_STORE || - store_mode == STORE_AND_GROW_NO_TRANSITION); + store_mode == STORE_AND_GROW_NO_TRANSITION || + store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || + store_mode == STORE_NO_TRANSITION_HANDLE_COW); Handle<String> name = isolate()->factory()->KeyedStoreElementMonomorphic_string(); @@ -530,7 +536,7 @@ Handle<Code> StubCache::ComputeStoreInterceptor(Handle<Name> name, Handle<Code> StubCache::ComputeKeyedStoreField(Handle<Name> name, Handle<JSObject> receiver, - int field_index, + LookupResult* lookup, Handle<Map> transition, StrictModeFlag strict_mode) { Code::StubType type = @@ -541,7 +547,7 @@ Handle<Code> StubCache::ComputeKeyedStoreField(Handle<Name> name, KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE); Handle<Code> code = - compiler.CompileStoreField(receiver, field_index, transition, name); + compiler.CompileStoreField(receiver, lookup, transition, name); JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -899,7 +905,9 @@ Handle<Code> StubCache::ComputeStoreElementPolymorphic( KeyedAccessStoreMode store_mode, StrictModeFlag strict_mode) { ASSERT(store_mode == STANDARD_STORE || - store_mode == STORE_AND_GROW_NO_TRANSITION); + store_mode == STORE_AND_GROW_NO_TRANSITION || + store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || + store_mode == STORE_NO_TRANSITION_HANDLE_COW); Handle<PolymorphicCodeCache> cache = isolate_->factory()->polymorphic_code_cache(); Code::ExtraICState extra_state = Code::ComputeExtraICState(store_mode, @@ -1580,7 +1588,7 @@ Handle<Code> LoadStubCompiler::CompileLoadViaGetter( Handle<Code> BaseStoreStubCompiler::CompileStoreField(Handle<JSObject> object, - int index, + LookupResult* lookup, Handle<Map> transition, Handle<Name> name) { Label miss, miss_restore_name; @@ -1590,7 +1598,7 @@ Handle<Code> BaseStoreStubCompiler::CompileStoreField(Handle<JSObject> object, // Generate store field code. GenerateStoreField(masm(), object, - index, + lookup, transition, name, receiver(), this->name(), value(), scratch1(), scratch2(), @@ -1660,10 +1668,19 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreElement( Handle<Map> receiver_map) { ElementsKind elements_kind = receiver_map->elements_kind(); bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; - Handle<Code> stub = - KeyedStoreElementStub(is_jsarray, - elements_kind, - store_mode_).GetCode(isolate()); + Handle<Code> stub; + if (FLAG_compiled_keyed_stores && + (receiver_map->has_fast_elements() || + receiver_map->has_external_array_elements())) { + stub = KeyedStoreFastElementStub( + is_jsarray, + elements_kind, + store_mode_).GetCode(isolate()); + } else { + stub = KeyedStoreElementStub(is_jsarray, + elements_kind, + store_mode_).GetCode(isolate()); + } __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK); @@ -1809,10 +1826,19 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic( strict_mode(), store_mode_).GetCode(isolate()); } else { - cached_stub = KeyedStoreElementStub( - is_js_array, - elements_kind, - store_mode_).GetCode(isolate()); + if (FLAG_compiled_keyed_stores && + (receiver_map->has_fast_elements() || + receiver_map->has_external_array_elements())) { + cached_stub = KeyedStoreFastElementStub( + is_js_array, + elements_kind, + store_mode_).GetCode(isolate()); + } else { + cached_stub = KeyedStoreElementStub( + is_js_array, + elements_kind, + store_mode_).GetCode(isolate()); + } } ASSERT(!cached_stub.is_null()); handlers.Add(cached_stub); diff --git a/deps/v8/src/stub-cache.h b/deps/v8/src/stub-cache.h index 7c455664c..bca3b7bca 100644 --- a/deps/v8/src/stub-cache.h +++ b/deps/v8/src/stub-cache.h @@ -85,10 +85,10 @@ class StubCache { Handle<Code> FindHandler( Handle<Name> name, + Handle<JSObject> receiver, Handle<JSObject> stub_holder, Code::Kind kind, - Code::StubType type, - Code::ExtraICState extra_state = Code::kNoExtraICState); + Code::StubType type); Handle<Code> ComputeMonomorphicIC(Handle<JSObject> receiver, Handle<Code> handler, @@ -161,7 +161,7 @@ class StubCache { Handle<Code> ComputeStoreField(Handle<Name> name, Handle<JSObject> object, - int field_index, + LookupResult* lookup, Handle<Map> transition, StrictModeFlag strict_mode); @@ -192,7 +192,7 @@ class StubCache { Handle<Code> ComputeKeyedStoreField(Handle<Name> name, Handle<JSObject> object, - int field_index, + LookupResult* lookup, Handle<Map> transition, StrictModeFlag strict_mode); @@ -511,7 +511,7 @@ class StubCompiler BASE_EMBEDDED { void GenerateStoreField(MacroAssembler* masm, Handle<JSObject> object, - int index, + LookupResult* lookup, Handle<Map> transition, Handle<Name> name, Register receiver_reg, @@ -782,7 +782,7 @@ class BaseStoreStubCompiler: public StubCompiler { virtual ~BaseStoreStubCompiler() { } Handle<Code> CompileStoreField(Handle<JSObject> object, - int index, + LookupResult* lookup, Handle<Map> transition, Handle<Name> name); diff --git a/deps/v8/src/symbol.js b/deps/v8/src/symbol.js index b7f9dc949..fb7476f43 100644 --- a/deps/v8/src/symbol.js +++ b/deps/v8/src/symbol.js @@ -27,13 +27,55 @@ "use strict"; -var $Symbol = function() { return %CreateSymbol() } -global.Symbol = $Symbol +var $Symbol = global.Symbol; -// Symbols only have a toString method and no prototype. -var SymbolDelegate = { - __proto__: null, - toString: $Object.prototype.toString +function SymbolConstructor(x) { + var value = + IS_SYMBOL(x) ? x : %CreateSymbol(IS_UNDEFINED(x) ? x : ToString(x)); + if (%_IsConstructCall()) { + %_SetValueOf(this, value); + } else { + return value; + } } -$Object.freeze(SymbolDelegate) +function SymbolGetName() { + var symbol = IS_SYMBOL_WRAPPER(this) ? %_ValueOf(this) : this; + if (!IS_SYMBOL(symbol)) { + throw MakeTypeError( + 'incompatible_method_receiver', ["Symbol.prototype.name", this]); + } + return %SymbolName(symbol); +} + +function SymbolToString() { + throw MakeTypeError('symbol_to_string'); +} + +function SymbolValueOf() { + // NOTE: Both Symbol objects and values can enter here as + // 'this'. This is not as dictated by ECMA-262. + if (!IS_SYMBOL(this) && !IS_SYMBOL_WRAPPER(this)) { + throw MakeTypeError( + 'incompatible_method_receiver', ["Symbol.prototype.valueOf", this]); + } + return %_ValueOf(this); +} + +//------------------------------------------------------------------- + +function SetUpSymbol() { + %CheckIsBootstrapping(); + + %SetCode($Symbol, SymbolConstructor); + %FunctionSetPrototype($Symbol, new $Symbol()); + %SetProperty($Symbol.prototype, "constructor", $Symbol, DONT_ENUM); + + InstallGetter($Symbol.prototype, "name", SymbolGetName); + InstallFunctions($Symbol.prototype, DONT_ENUM, $Array( + "toString", SymbolToString, + "valueOf", SymbolValueOf + )); +} + +SetUpSymbol(); diff --git a/deps/v8/src/token.h b/deps/v8/src/token.h index 4078a15cd..04d7f7639 100644 --- a/deps/v8/src/token.h +++ b/deps/v8/src/token.h @@ -174,6 +174,7 @@ namespace internal { K(EXPORT, "export", 0) \ K(IMPORT, "import", 0) \ K(LET, "let", 0) \ + K(YIELD, "yield", 0) \ \ /* Illegal token - not able to scan. */ \ T(ILLEGAL, "ILLEGAL", 0) \ diff --git a/deps/v8/src/type-info.cc b/deps/v8/src/type-info.cc index 6ac05547a..39a01f59e 100644 --- a/deps/v8/src/type-info.cc +++ b/deps/v8/src/type-info.cc @@ -126,9 +126,9 @@ bool TypeFeedbackOracle::StoreIsMonomorphicNormal(TypeFeedbackId ast_id) { if (map_or_code->IsMap()) return true; if (map_or_code->IsCode()) { Handle<Code> code = Handle<Code>::cast(map_or_code); - bool standard_store = - Code::GetKeyedAccessStoreMode(code->extra_ic_state()) == - STANDARD_STORE; + bool standard_store = FLAG_compiled_keyed_stores || + (Code::GetKeyedAccessStoreMode(code->extra_ic_state()) == + STANDARD_STORE); bool preliminary_checks = code->is_keyed_store_stub() && standard_store && @@ -146,9 +146,9 @@ bool TypeFeedbackOracle::StoreIsPolymorphic(TypeFeedbackId ast_id) { Handle<Object> map_or_code = GetInfo(ast_id); if (map_or_code->IsCode()) { Handle<Code> code = Handle<Code>::cast(map_or_code); - bool standard_store = - Code::GetKeyedAccessStoreMode(code->extra_ic_state()) == - STANDARD_STORE; + bool standard_store = FLAG_compiled_keyed_stores || + (Code::GetKeyedAccessStoreMode(code->extra_ic_state()) == + STANDARD_STORE); return code->is_keyed_store_stub() && standard_store && code->ic_state() == POLYMORPHIC; } @@ -283,11 +283,12 @@ Handle<JSObject> TypeFeedbackOracle::GetPrototypeForPrimitiveCheck( case RECEIVER_MAP_CHECK: UNREACHABLE(); break; - case SYMBOL_CHECK: - return Handle<JSObject>(native_context_->symbol_delegate()); case STRING_CHECK: function = native_context_->string_function(); break; + case SYMBOL_CHECK: + function = native_context_->symbol_function(); + break; case NUMBER_CHECK: function = native_context_->number_function(); break; diff --git a/deps/v8/src/typedarray.js b/deps/v8/src/typedarray.js new file mode 100644 index 000000000..c3e3ebd66 --- /dev/null +++ b/deps/v8/src/typedarray.js @@ -0,0 +1,98 @@ +// 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"; + +var $ArrayBuffer = global.__ArrayBuffer; + +function ArrayBufferConstructor(byteLength) { // length = 1 + if (%_IsConstructCall()) { + var l = TO_POSITIVE_INTEGER(byteLength); + %ArrayBufferInitialize(this, l); + } else { + return new $ArrayBuffer(byteLength); + } +} + +function ArrayBufferGetByteLength() { + if (!IS_ARRAYBUFFER(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['ArrayBuffer.prototype.byteLength', this]); + } + return %ArrayBufferGetByteLength(this); +} + +// ES6 Draft 15.13.5.5.3 +function ArrayBufferSlice(start, end) { + if (!IS_ARRAYBUFFER(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['ArrayBuffer.prototype.slice', this]); + } + + var relativeStart = TO_INTEGER(start); + var first; + if (relativeStart < 0) { + first = MathMax(this.byteLength + relativeStart, 0); + } else { + first = MathMin(relativeStart, this.byteLength); + } + var relativeEnd = IS_UNDEFINED(end) ? this.byteLength : TO_INTEGER(end); + var fin; + if (relativeEnd < 0) { + fin = MathMax(this.byteLength + relativeEnd, 0); + } else { + fin = MathMin(relativeEnd, this.byteLength); + } + + var newLen = fin - first; + // TODO(dslomov): implement inheritance + var result = new $ArrayBuffer(newLen); + + %ArrayBufferSliceImpl(this, result, first); + return result; +} + + + +// ------------------------------------------------------------------- + +(function () { + %CheckIsBootstrapping(); + + // Set up the Uint16Array constructor function. + %SetCode($ArrayBuffer, ArrayBufferConstructor); + + // Set up the constructor property on the ArrayBuffer prototype object. + %SetProperty($ArrayBuffer.prototype, "constructor", $ArrayBuffer, DONT_ENUM); + + InstallGetter($ArrayBuffer.prototype, "byteLength", ArrayBufferGetByteLength); + + InstallFunctions($ArrayBuffer.prototype, DONT_ENUM, $Array( + "slice", ArrayBufferSlice + )); + +})(); diff --git a/deps/v8/src/v8globals.h b/deps/v8/src/v8globals.h index 8874cfb25..4b4d312f9 100644 --- a/deps/v8/src/v8globals.h +++ b/deps/v8/src/v8globals.h @@ -296,7 +296,7 @@ enum CallFunctionFlags { enum InlineCacheHolderFlag { OWN_MAP, // For fast properties objects. - DELEGATE_MAP // For slow properties objects (except GlobalObjects). + PROTOTYPE_MAP // For slow properties objects (except GlobalObjects). }; diff --git a/deps/v8/src/v8natives.js b/deps/v8/src/v8natives.js index 24ad22d96..d9dc09651 100644 --- a/deps/v8/src/v8natives.js +++ b/deps/v8/src/v8natives.js @@ -233,7 +233,6 @@ $Object.prototype.constructor = $Object; function ObjectToString() { if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]"; if (IS_NULL(this)) return "[object Null]"; - if (IS_SYMBOL(this)) return "[object Symbol]"; return "[object " + %_ClassOf(ToObject(this)) + "]"; } @@ -257,6 +256,9 @@ function ObjectValueOf() { // ECMA-262 - 15.2.4.5 function ObjectHasOwnProperty(V) { if (%IsJSProxy(this)) { + // TODO(rossberg): adjust once there is a story for symbols vs proxies. + if (IS_SYMBOL(V)) return false; + var handler = %GetHandler(this); return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, ToName(V)); } @@ -279,6 +281,9 @@ function ObjectIsPrototypeOf(V) { function ObjectPropertyIsEnumerable(V) { var P = ToName(V); if (%IsJSProxy(this)) { + // TODO(rossberg): adjust once there is a story for symbols vs proxies. + if (IS_SYMBOL(V)) return false; + var desc = GetOwnProperty(this, P); return IS_UNDEFINED(desc) ? false : desc.isEnumerable(); } @@ -646,6 +651,9 @@ function CallTrap2(handler, name, defaultTrap, x, y) { function GetOwnProperty(obj, v) { var p = ToName(v); if (%IsJSProxy(obj)) { + // TODO(rossberg): adjust once there is a story for symbols vs proxies. + if (IS_SYMBOL(v)) return void 0; + var handler = %GetHandler(obj); var descriptor = CallTrap1(handler, "getOwnPropertyDescriptor", void 0, p); if (IS_UNDEFINED(descriptor)) return descriptor; @@ -686,6 +694,9 @@ function Delete(obj, p, should_throw) { // Harmony proxies. function DefineProxyProperty(obj, p, attributes, should_throw) { + // TODO(rossberg): adjust once there is a story for symbols vs proxies. + if (IS_SYMBOL(p)) return false; + var handler = %GetHandler(obj); var result = CallTrap2(handler, "defineProperty", void 0, p, attributes); if (!ToBoolean(result)) { @@ -865,7 +876,7 @@ function DefineArrayProperty(obj, p, desc, should_throw) { // DefineObjectProperty() to modify its value. // Step 3 - Special handling for length property. - if (p == "length") { + if (p === "length") { var length = obj.length; if (!desc.hasValue()) { return DefineObjectProperty(obj, "length", desc, should_throw); @@ -951,6 +962,9 @@ function DefineArrayProperty(obj, p, desc, should_throw) { // ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies. function DefineOwnProperty(obj, p, desc, should_throw) { if (%IsJSProxy(obj)) { + // TODO(rossberg): adjust once there is a story for symbols vs proxies. + if (IS_SYMBOL(p)) return false; + var attributes = FromGenericPropertyDescriptor(desc); return DefineProxyProperty(obj, p, attributes, should_throw); } else if (IS_ARRAY(obj)) { @@ -988,16 +1002,20 @@ function ToNameArray(obj, trap, includeSymbols) { } var n = ToUint32(obj.length); var array = new $Array(n); + var realLength = 0; var names = { __proto__: null }; // TODO(rossberg): use sets once ready. for (var index = 0; index < n; index++) { var s = ToName(obj[index]); + // TODO(rossberg): adjust once there is a story for symbols vs proxies. if (IS_SYMBOL(s) && !includeSymbols) continue; if (%HasLocalProperty(names, s)) { throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]); } array[index] = s; + ++realLength; names[s] = 0; } + array.length = realLength; return array; } @@ -1011,7 +1029,7 @@ function ObjectGetOwnPropertyNames(obj) { if (%IsJSProxy(obj)) { var handler = %GetHandler(obj); var names = CallTrap0(handler, "getOwnPropertyNames", void 0); - return ToNameArray(names, "getOwnPropertyNames", true); + return ToNameArray(names, "getOwnPropertyNames", false); } var nameArrays = new InternalArray(); @@ -1037,7 +1055,7 @@ function ObjectGetOwnPropertyNames(obj) { // Find all the named properties. // Get the local property names. - nameArrays.push(%GetLocalPropertyNames(obj)); + nameArrays.push(%GetLocalPropertyNames(obj, false)); // Get names for named interceptor properties if any. if ((interceptorInfo & 2) != 0) { @@ -1057,7 +1075,8 @@ function ObjectGetOwnPropertyNames(obj) { var propertySet = { __proto__: null }; var j = 0; for (var i = 0; i < propertyNames.length; ++i) { - var name = ToName(propertyNames[i]); + if (IS_SYMBOL(propertyNames[i])) continue; + var name = ToString(propertyNames[i]); // We need to check for the exact property value since for intrinsic // properties like toString if(propertySet["toString"]) will always // succeed. diff --git a/deps/v8/src/v8utils.h b/deps/v8/src/v8utils.h index 793d34d9c..b5c8f084e 100644 --- a/deps/v8/src/v8utils.h +++ b/deps/v8/src/v8utils.h @@ -111,6 +111,7 @@ int WriteAsCFile(const char* filename, const char* varname, const char* str, int size, bool verbose = true); +// ---------------------------------------------------------------------------- // Data structures template <typename T> @@ -120,21 +121,24 @@ inline Vector< Handle<Object> > HandleVector(v8::internal::Handle<T>* elms, reinterpret_cast<v8::internal::Handle<Object>*>(elms), length); } + +// ---------------------------------------------------------------------------- // Memory -// Copies data from |src| to |dst|. The data spans MUST not overlap. +// Copies data from |src| to |dst|. The data spans must not overlap. template <typename T> inline void CopyWords(T* dst, T* src, int num_words) { STATIC_ASSERT(sizeof(T) == kPointerSize); ASSERT(Min(dst, src) + num_words <= Max(dst, src)); ASSERT(num_words > 0); - // Use block copying memcpy if the segment we're copying is + // Use block copying OS::MemCopy if the segment we're copying is // enough to justify the extra call/setup overhead. static const int kBlockCopyLimit = 16; + STATIC_ASSERT(kBlockCopyLimit * kPointerSize >= OS::kMinComplexMemCopy); if (num_words >= kBlockCopyLimit) { - memcpy(dst, src, num_words * kPointerSize); + OS::MemCopy(dst, src, num_words * kPointerSize); } else { int remaining = num_words; do { @@ -145,6 +149,29 @@ inline void CopyWords(T* dst, T* src, int num_words) { } +// Copies data from |src| to |dst|. The data spans must not overlap. +template <typename T> +inline void CopyBytes(T* dst, T* src, size_t num_bytes) { + STATIC_ASSERT(sizeof(T) == 1); + ASSERT(Min(dst, src) + num_bytes <= Max(dst, src)); + if (num_bytes == 0) return; + + // Use block copying OS::MemCopy if the segment we're copying is + // enough to justify the extra call/setup overhead. + static const int kBlockCopyLimit = OS::kMinComplexMemCopy; + + if (num_bytes >= static_cast<size_t>(kBlockCopyLimit)) { + OS::MemCopy(dst, src, num_bytes); + } else { + size_t remaining = num_bytes; + do { + remaining--; + *dst++ = *src++; + } while (remaining > 0); + } +} + + template <typename T, typename U> inline void MemsetPointer(T** dest, U* value, int counter) { #ifdef DEBUG diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index 4bb5a499d..64ed98d46 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -34,7 +34,7 @@ // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 3 #define MINOR_VERSION 17 -#define BUILD_NUMBER 13 +#define BUILD_NUMBER 16 #define PATCH_LEVEL 0 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/x64/builtins-x64.cc b/deps/v8/src/x64/builtins-x64.cc index 0b70c1a0c..2da3de2b9 100644 --- a/deps/v8/src/x64/builtins-x64.cc +++ b/deps/v8/src/x64/builtins-x64.cc @@ -220,12 +220,12 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, __ movzxbq(rdi, FieldOperand(rax, Map::kInstanceSizeOffset)); __ shl(rdi, Immediate(kPointerSizeLog2)); // rdi: size of new object - __ AllocateInNewSpace(rdi, - rbx, - rdi, - no_reg, - &rt_call, - NO_ALLOCATION_FLAGS); + __ Allocate(rdi, + rbx, + rdi, + no_reg, + &rt_call, + NO_ALLOCATION_FLAGS); // Allocated the JSObject, now initialize the fields. // rax: initial map // rbx: JSObject (not HeapObject tagged - the actual address). @@ -287,14 +287,14 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, // rbx: JSObject // rdi: start of next object (will be start of FixedArray) // rdx: number of elements in properties array - __ AllocateInNewSpace(FixedArray::kHeaderSize, - times_pointer_size, - rdx, - rdi, - rax, - no_reg, - &undo_allocation, - RESULT_CONTAINS_TOP); + __ Allocate(FixedArray::kHeaderSize, + times_pointer_size, + rdx, + rdi, + rax, + no_reg, + &undo_allocation, + RESULT_CONTAINS_TOP); // Initialize the FixedArray. // rbx: JSObject @@ -416,10 +416,6 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx); __ j(above_equal, &exit); - // Symbols are "objects". - __ CmpInstanceType(rcx, SYMBOL_TYPE); - __ j(equal, &exit); - // Throw away the result of the constructor invocation and use the // on-stack receiver as the result. __ bind(&use_receiver); @@ -1216,14 +1212,14 @@ static void AllocateJSArray(MacroAssembler* masm, // requested elements. SmiIndex index = masm->SmiToIndex(kScratchRegister, array_size, kPointerSizeLog2); - __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize, - index.scale, - index.reg, - result, - elements_array_end, - scratch, - gc_required, - TAG_OBJECT); + __ Allocate(JSArray::kSize + FixedArray::kHeaderSize, + index.scale, + index.reg, + result, + elements_array_end, + scratch, + gc_required, + TAG_OBJECT); // Allocated the JSArray. Now initialize the fields except for the elements // array. diff --git a/deps/v8/src/x64/code-stubs-x64.cc b/deps/v8/src/x64/code-stubs-x64.cc index 04c3e6837..fffd37f51 100644 --- a/deps/v8/src/x64/code-stubs-x64.cc +++ b/deps/v8/src/x64/code-stubs-x64.cc @@ -62,6 +62,17 @@ void KeyedLoadFastElementStub::InitializeInterfaceDescriptor( } +void KeyedStoreFastElementStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + static Register registers[] = { rdx, rcx, rax }; + descriptor->register_param_count_ = 3; + descriptor->register_params_ = registers; + descriptor->deoptimization_handler_ = + FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure); +} + + void TransitionElementsKindStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { @@ -84,7 +95,7 @@ static void InitializeArrayConstructorDescriptor(Isolate* isolate, // stack param count needs (constructor pointer, and single argument) descriptor->stack_parameter_count_ = &rax; descriptor->register_params_ = registers; - descriptor->extra_expression_stack_count_ = 1; + descriptor->function_mode_ = JS_FUNCTION_STUB_MODE; descriptor->deoptimization_handler_ = FUNCTION_ADDR(ArrayConstructor_StubFailure); } @@ -2375,34 +2386,6 @@ void MathPowStub::Generate(MacroAssembler* masm) { } -void ArrayLengthStub::Generate(MacroAssembler* masm) { - Label miss; - Register receiver; - if (kind() == Code::KEYED_LOAD_IC) { - // ----------- S t a t e ------------- - // -- rax : key - // -- rdx : receiver - // -- rsp[0] : return address - // ----------------------------------- - __ Cmp(rax, masm->isolate()->factory()->length_string()); - __ j(not_equal, &miss); - receiver = rdx; - } else { - ASSERT(kind() == Code::LOAD_IC); - // ----------- S t a t e ------------- - // -- rax : receiver - // -- rcx : name - // -- rsp[0] : return address - // ----------------------------------- - receiver = rax; - } - - StubCompiler::GenerateLoadArrayLength(masm, receiver, r8, &miss); - __ bind(&miss); - StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind())); -} - - void FunctionPrototypeStub::Generate(MacroAssembler* masm) { Label miss; Register receiver; @@ -2652,7 +2635,7 @@ void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { __ addq(r8, Immediate(Heap::kArgumentsObjectSize)); // Do the allocation of all three objects in one go. - __ AllocateInNewSpace(r8, rax, rdx, rdi, &runtime, TAG_OBJECT); + __ Allocate(r8, rax, rdx, rdi, &runtime, TAG_OBJECT); // rax = address of new object(s) (tagged) // rcx = argument count (untagged) @@ -2870,7 +2853,7 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { __ addq(rcx, Immediate(Heap::kArgumentsObjectSizeStrict)); // Do the allocation of both objects in one go. - __ AllocateInNewSpace(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT); + __ Allocate(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT); // Get the arguments boilerplate from the current native context. __ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); @@ -3403,14 +3386,14 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) { // Allocate RegExpResult followed by FixedArray with size in rbx. // JSArray: [Map][empty properties][Elements][Length-smi][index][input] // Elements: [Map][Length][..elements..] - __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize, - times_pointer_size, - rbx, // In: Number of elements. - rax, // Out: Start of allocation (tagged). - rcx, // Out: End of allocation. - rdx, // Scratch register - &slowcase, - TAG_OBJECT); + __ Allocate(JSRegExpResult::kSize + FixedArray::kHeaderSize, + times_pointer_size, + rbx, // In: Number of elements. + rax, // Out: Start of allocation (tagged). + rcx, // Out: End of allocation. + rdx, // Scratch register + &slowcase, + TAG_OBJECT); // rax: Start of allocated area, object-tagged. // rbx: Number of array elements as int32. // r8: Number of array elements as smi. @@ -6800,8 +6783,10 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) { __ movq(rbx, MemOperand(rbp, parameter_count_offset)); masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE); __ pop(rcx); - __ lea(rsp, MemOperand(rsp, rbx, times_pointer_size, - extra_expression_stack_count_ * kPointerSize)); + int additional_offset = function_mode_ == JS_FUNCTION_STUB_MODE + ? kPointerSize + : 0; + __ lea(rsp, MemOperand(rsp, rbx, times_pointer_size, additional_offset)); __ jmp(rcx); // Return to IC Miss stub, continuation still on stack. } diff --git a/deps/v8/src/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc index fa8b44a41..6f32f7cf0 100644 --- a/deps/v8/src/x64/codegen-x64.cc +++ b/deps/v8/src/x64/codegen-x64.cc @@ -347,7 +347,7 @@ void ElementsTransitionGenerator::GenerateSmiToDouble( // Allocate new backing store. __ bind(&new_backing_store); __ lea(rdi, Operand(r9, times_pointer_size, FixedArray::kHeaderSize)); - __ AllocateInNewSpace(rdi, r14, r11, r15, fail, TAG_OBJECT); + __ Allocate(rdi, r14, r11, r15, fail, TAG_OBJECT); // Set backing store's map __ LoadRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex); __ movq(FieldOperand(r14, HeapObject::kMapOffset), rdi); @@ -435,7 +435,7 @@ void ElementsTransitionGenerator::GenerateDoubleToObject( // r8 : source FixedDoubleArray // r9 : number of elements __ lea(rdi, Operand(r9, times_pointer_size, FixedArray::kHeaderSize)); - __ AllocateInNewSpace(rdi, r11, r14, r15, &gc_required, TAG_OBJECT); + __ Allocate(rdi, r11, r14, r15, &gc_required, TAG_OBJECT); // r11: destination FixedArray __ LoadRoot(rdi, Heap::kFixedArrayMapRootIndex); __ movq(FieldOperand(r11, HeapObject::kMapOffset), rdi); @@ -769,7 +769,7 @@ void Code::PatchPlatformCodeAge(byte* sequence, uint32_t young_length; byte* young_sequence = GetNoCodeAgeSequence(&young_length); if (age == kNoAge) { - memcpy(sequence, young_sequence, young_length); + CopyBytes(sequence, young_sequence, young_length); CPU::FlushICache(sequence, young_length); } else { Code* stub = GetCodeAgeStub(age, parity); diff --git a/deps/v8/src/x64/full-codegen-x64.cc b/deps/v8/src/x64/full-codegen-x64.cc index 8ff12df36..322479dec 100644 --- a/deps/v8/src/x64/full-codegen-x64.cc +++ b/deps/v8/src/x64/full-codegen-x64.cc @@ -2678,28 +2678,6 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( } -void FullCodeGenerator::EmitIsSymbol(CallRuntime* expr) { - ZoneList<Expression*>* args = expr->arguments(); - ASSERT(args->length() == 1); - - VisitForAccumulatorValue(args->at(0)); - - Label materialize_true, materialize_false; - Label* if_true = NULL; - Label* if_false = NULL; - Label* fall_through = NULL; - context()->PrepareTest(&materialize_true, &materialize_false, - &if_true, &if_false, &fall_through); - - __ JumpIfSmi(rax, if_false); - __ CmpObjectType(rax, SYMBOL_TYPE, rbx); - PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - Split(equal, if_true, if_false, fall_through); - - context()->Plug(if_true, if_false); -} - - void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) { ZoneList<Expression*>* args = expr->arguments(); ASSERT(args->length() == 1); @@ -4271,6 +4249,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ testb(FieldOperand(rdx, Map::kBitFieldOffset), Immediate(1 << Map::kIsUndetectable)); Split(zero, if_true, if_false, fall_through); + } else if (check->Equals(isolate()->heap()->symbol_string())) { + __ JumpIfSmi(rax, if_false); + __ CmpObjectType(rax, SYMBOL_TYPE, rdx); + Split(equal, if_true, if_false, fall_through); } else if (check->Equals(isolate()->heap()->boolean_string())) { __ CompareRoot(rax, Heap::kTrueValueRootIndex); __ j(equal, if_true); @@ -4302,10 +4284,6 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, __ CompareRoot(rax, Heap::kNullValueRootIndex); __ j(equal, if_true); } - if (FLAG_harmony_symbols) { - __ CmpObjectType(rax, SYMBOL_TYPE, rdx); - __ j(equal, if_true); - } __ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx); __ j(below, if_false); __ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); diff --git a/deps/v8/src/x64/lithium-codegen-x64.cc b/deps/v8/src/x64/lithium-codegen-x64.cc index b9bd30bb1..817a9d35e 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.cc +++ b/deps/v8/src/x64/lithium-codegen-x64.cc @@ -1574,13 +1574,6 @@ void LCodeGen::DoConstantT(LConstantT* instr) { } -void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { - Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->value()); - __ movq(result, FieldOperand(array, JSArray::kLengthOffset)); -} - - void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) { Register result = ToRegister(instr->result()); Register array = ToRegister(instr->value()); @@ -5129,7 +5122,7 @@ void LCodeGen::DoAllocate(LAllocate* instr) { __ Allocate(size, result, temp, no_reg, deferred->entry(), flags); } else { Register size = ToRegister(instr->size()); - __ AllocateInNewSpace(size, result, temp, no_reg, deferred->entry(), flags); + __ Allocate(size, result, temp, no_reg, deferred->entry(), flags); } __ bind(deferred->exit()); @@ -5538,6 +5531,11 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, Immediate(1 << Map::kIsUndetectable)); final_branch_condition = zero; + } else if (type_name->Equals(heap()->symbol_string())) { + __ JumpIfSmi(input, false_label); + __ CmpObjectType(input, SYMBOL_TYPE, input); + final_branch_condition = equal; + } else if (type_name->Equals(heap()->boolean_string())) { __ CompareRoot(input, Heap::kTrueValueRootIndex); __ j(equal, true_label); @@ -5572,13 +5570,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, __ CompareRoot(input, Heap::kNullValueRootIndex); __ j(equal, true_label); } - if (FLAG_harmony_symbols) { - __ CmpObjectType(input, SYMBOL_TYPE, input); - __ j(equal, true_label); - __ CmpInstanceType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); - } else { - __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); - } + __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); __ j(below, false_label); __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); __ j(above, false_label); diff --git a/deps/v8/src/x64/lithium-x64.cc b/deps/v8/src/x64/lithium-x64.cc index 16248ee17..9a3166ee4 100644 --- a/deps/v8/src/x64/lithium-x64.cc +++ b/deps/v8/src/x64/lithium-x64.cc @@ -879,6 +879,35 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { LInstruction* instr = current->CompileToLithium(this); if (instr != NULL) { +#if DEBUG + // Make sure that the lithium instruction has either no fixed register + // constraints in temps or the result OR no uses that are only used at + // start. If this invariant doesn't hold, the register allocator can decide + // to insert a split of a range immediately before the instruction due to an + // already allocated register needing to be used for the instruction's fixed + // register constraint. In this case, The register allocator won't see an + // interference between the split child and the use-at-start (it would if + // the it was just a plain use), so it is free to move the split child into + // the same register that is used for the use-at-start. + // See https://code.google.com/p/chromium/issues/detail?id=201590 + if (!(instr->ClobbersRegisters() && instr->ClobbersDoubleRegisters())) { + int fixed = 0; + int used_at_start = 0; + for (UseIterator it(instr); !it.Done(); it.Advance()) { + LUnallocated* operand = LUnallocated::cast(it.Current()); + if (operand->IsUsedAtStart()) ++used_at_start; + } + if (instr->Output() != NULL) { + if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed; + } + for (TempIterator it(instr); !it.Done(); it.Advance()) { + LUnallocated* operand = LUnallocated::cast(it.Current()); + if (operand->HasFixedPolicy()) ++fixed; + } + ASSERT(fixed == 0 || used_at_start == 0); + } +#endif + if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) { instr = AssignPointerMap(instr); } @@ -1632,12 +1661,6 @@ LInstruction* LChunkBuilder::DoClassOfTestAndBranch( } -LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) { - LOperand* array = UseRegisterAtStart(instr->value()); - return DefineAsRegister(new(zone()) LJSArrayLength(array)); -} - - LInstruction* LChunkBuilder::DoFixedArrayBaseLength( HFixedArrayBaseLength* instr) { LOperand* array = UseRegisterAtStart(instr->value()); diff --git a/deps/v8/src/x64/lithium-x64.h b/deps/v8/src/x64/lithium-x64.h index 9e3e836ed..051f9a469 100644 --- a/deps/v8/src/x64/lithium-x64.h +++ b/deps/v8/src/x64/lithium-x64.h @@ -121,7 +121,6 @@ class LCodeGen; V(IsStringAndBranch) \ V(IsSmiAndBranch) \ V(IsUndetectableAndBranch) \ - V(JSArrayLength) \ V(Label) \ V(LazyBailout) \ V(LoadContextSlot) \ @@ -1109,19 +1108,6 @@ class LCmpMapAndBranch: public LTemplateInstruction<0, 1, 0> { }; -class LJSArrayLength: public LTemplateInstruction<1, 1, 0> { - public: - explicit LJSArrayLength(LOperand* value) { - inputs_[0] = value; - } - - LOperand* value() { return inputs_[0]; } - - DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length") - DECLARE_HYDROGEN_ACCESSOR(JSArrayLength) -}; - - class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> { public: explicit LFixedArrayBaseLength(LOperand* value) { @@ -2034,7 +2020,7 @@ class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> { }; -class LTransitionElementsKind: public LTemplateInstruction<1, 1, 2> { +class LTransitionElementsKind: public LTemplateInstruction<0, 1, 2> { public: LTransitionElementsKind(LOperand* object, LOperand* new_map_temp, diff --git a/deps/v8/src/x64/macro-assembler-x64.cc b/deps/v8/src/x64/macro-assembler-x64.cc index 9ecf66c5e..6c1c19df3 100644 --- a/deps/v8/src/x64/macro-assembler-x64.cc +++ b/deps/v8/src/x64/macro-assembler-x64.cc @@ -3830,16 +3830,15 @@ void MacroAssembler::Allocate(int object_size, } -void MacroAssembler::AllocateInNewSpace(int header_size, - ScaleFactor element_size, - Register element_count, - Register result, - Register result_end, - Register scratch, - Label* gc_required, - AllocationFlags flags) { +void MacroAssembler::Allocate(int header_size, + ScaleFactor element_size, + Register element_count, + Register result, + Register result_end, + Register scratch, + Label* gc_required, + AllocationFlags flags) { ASSERT((flags & SIZE_IN_WORDS) == 0); - ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0); if (!FLAG_inline_new) { if (emit_debug_code()) { // Trash the registers to simulate an allocation failure. @@ -3866,15 +3865,15 @@ void MacroAssembler::AllocateInNewSpace(int header_size, } // Calculate new top and bail out if new space is exhausted. - ExternalReference new_space_allocation_limit = - ExternalReference::new_space_allocation_limit_address(isolate()); + ExternalReference allocation_limit = + AllocationUtils::GetAllocationLimitReference(isolate(), flags); // We assume that element_count*element_size + header_size does not // overflow. lea(result_end, Operand(element_count, element_size, header_size)); addq(result_end, result); j(carry, gc_required); - Operand limit_operand = ExternalOperand(new_space_allocation_limit); + Operand limit_operand = ExternalOperand(allocation_limit); cmpq(result_end, limit_operand); j(above, gc_required); @@ -3889,14 +3888,13 @@ void MacroAssembler::AllocateInNewSpace(int header_size, } -void MacroAssembler::AllocateInNewSpace(Register object_size, - Register result, - Register result_end, - Register scratch, - Label* gc_required, - AllocationFlags flags) { +void MacroAssembler::Allocate(Register object_size, + Register result, + Register result_end, + Register scratch, + Label* gc_required, + AllocationFlags flags) { ASSERT((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0); - ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0); if (!FLAG_inline_new) { if (emit_debug_code()) { // Trash the registers to simulate an allocation failure. @@ -3916,14 +3914,14 @@ void MacroAssembler::AllocateInNewSpace(Register object_size, LoadAllocationTopHelper(result, scratch, flags); // Calculate new top and bail out if new space is exhausted. - ExternalReference new_space_allocation_limit = - ExternalReference::new_space_allocation_limit_address(isolate()); + ExternalReference allocation_limit = + AllocationUtils::GetAllocationLimitReference(isolate(), flags); if (!object_size.is(result_end)) { movq(result_end, object_size); } addq(result_end, result); j(carry, gc_required); - Operand limit_operand = ExternalOperand(new_space_allocation_limit); + Operand limit_operand = ExternalOperand(allocation_limit); cmpq(result_end, limit_operand); j(above, gc_required); @@ -3991,14 +3989,14 @@ void MacroAssembler::AllocateTwoByteString(Register result, } // Allocate two byte string in new space. - AllocateInNewSpace(SeqTwoByteString::kHeaderSize, - times_1, - scratch1, - result, - scratch2, - scratch3, - gc_required, - TAG_OBJECT); + Allocate(SeqTwoByteString::kHeaderSize, + times_1, + scratch1, + result, + scratch2, + scratch3, + gc_required, + TAG_OBJECT); // Set the map, length and hash field. LoadRoot(kScratchRegister, Heap::kStringMapRootIndex); @@ -4029,14 +4027,14 @@ void MacroAssembler::AllocateAsciiString(Register result, } // Allocate ASCII string in new space. - AllocateInNewSpace(SeqOneByteString::kHeaderSize, - times_1, - scratch1, - result, - scratch2, - scratch3, - gc_required, - TAG_OBJECT); + Allocate(SeqOneByteString::kHeaderSize, + times_1, + scratch1, + result, + scratch2, + scratch3, + gc_required, + TAG_OBJECT); // Set the map, length and hash field. LoadRoot(kScratchRegister, Heap::kAsciiStringMapRootIndex); diff --git a/deps/v8/src/x64/macro-assembler-x64.h b/deps/v8/src/x64/macro-assembler-x64.h index df5215991..3381a5b7b 100644 --- a/deps/v8/src/x64/macro-assembler-x64.h +++ b/deps/v8/src/x64/macro-assembler-x64.h @@ -1042,21 +1042,21 @@ class MacroAssembler: public Assembler { Label* gc_required, AllocationFlags flags); - void AllocateInNewSpace(int header_size, - ScaleFactor element_size, - Register element_count, - Register result, - Register result_end, - Register scratch, - Label* gc_required, - AllocationFlags flags); + void Allocate(int header_size, + ScaleFactor element_size, + Register element_count, + Register result, + Register result_end, + Register scratch, + Label* gc_required, + AllocationFlags flags); - void AllocateInNewSpace(Register object_size, - Register result, - Register result_end, - Register scratch, - Label* gc_required, - AllocationFlags flags); + void Allocate(Register object_size, + Register result, + Register result_end, + Register scratch, + Label* gc_required, + AllocationFlags flags); // Undo allocation in new space. The object passed and objects allocated after // it will no longer be allocated. Make sure that no pointers are left to the diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc index 69d7a91b2..7e900dbe6 100644 --- a/deps/v8/src/x64/stub-cache-x64.cc +++ b/deps/v8/src/x64/stub-cache-x64.cc @@ -716,7 +716,7 @@ void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm, // but may be destroyed if store is successful. void StubCompiler::GenerateStoreField(MacroAssembler* masm, Handle<JSObject> object, - int index, + LookupResult* lookup, Handle<Map> transition, Handle<Name> name, Register receiver_reg, @@ -726,16 +726,6 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, Register scratch2, Label* miss_label, Label* miss_restore_name) { - LookupResult lookup(masm->isolate()); - object->Lookup(*name, &lookup); - if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) { - // In sloppy mode, we could just return the value and be done. However, we - // might be in strict mode, where we have to throw. Since we cannot tell, - // go into slow case unconditionally. - __ jmp(miss_label); - return; - } - // Check that the map of the object hasn't changed. CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS : REQUIRE_EXACT_MAP; @@ -750,8 +740,9 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, // Check that we are allowed to write this. if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { JSObject* holder; - if (lookup.IsFound()) { - holder = lookup.holder(); + // holder == object indicates that no property was found. + if (lookup->holder() != *object) { + holder = lookup->holder(); } else { // Find the top object. holder = *object; @@ -759,8 +750,19 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, holder = JSObject::cast(holder->GetPrototype()); } while (holder->GetPrototype()->IsJSObject()); } - CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg, - scratch1, scratch2, name, miss_restore_name); + Register holder_reg = CheckPrototypes( + object, receiver_reg, Handle<JSObject>(holder), name_reg, + scratch1, scratch2, name, miss_restore_name); + // If no property was found, and the holder (the last object in the + // prototype chain) is in slow mode, we need to do a negative lookup on the + // holder. + if (lookup->holder() == *object && + !holder->HasFastProperties() && + !holder->IsJSGlobalProxy() && + !holder->IsJSGlobalObject()) { + GenerateDictionaryNegativeLookup( + masm, miss_restore_name, holder_reg, name, scratch1, scratch2); + } } // Stub never generated for non-global objects that require access @@ -784,6 +786,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, return; } + int index; if (!transition.is_null()) { // Update the map of the object. __ Move(scratch1, transition); @@ -798,6 +801,10 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); + index = transition->instance_descriptors()->GetFieldIndex( + transition->LastAdded()); + } else { + index = lookup->GetFieldIndex().field_index(); } // Adjust for the number of properties stored in the object. Even in the @@ -2174,6 +2181,12 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object, // Check that the object is a symbol. __ CmpObjectType(rdx, SYMBOL_TYPE, rax); __ j(not_equal, &miss); + // Check that the maps starting from the prototype haven't changed. + GenerateDirectLoadGlobalFunctionPrototype( + masm(), Context::SYMBOL_FUNCTION_INDEX, rax, &miss); + CheckPrototypes( + Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))), + rax, holder, rbx, rdx, rdi, name, &miss); break; case NUMBER_CHECK: { diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index e06cb77c6..a9780f033 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -8376,7 +8376,7 @@ THREADED_TEST(Regress91517) { // Call the runtime version of GetLocalPropertyNames() on the natively // created object through JavaScript. context->Global()->Set(v8_str("obj"), o4); - CompileRun("var names = %GetLocalPropertyNames(obj);"); + CompileRun("var names = %GetLocalPropertyNames(obj, true);"); ExpectInt32("names.length", 1006); ExpectTrue("names.indexOf(\"baz\") >= 0"); @@ -16054,15 +16054,17 @@ THREADED_TEST(TwoByteStringInAsciiCons) { CHECK(flat_string->IsTwoByteRepresentation()); - // At this point, we should have a Cons string which is flat and ASCII, - // with a first half that is a two-byte string (although it only contains - // ASCII characters). This is a valid sequence of steps, and it can happen - // in real pages. - - CHECK(string->IsOneByteRepresentation()); - i::ConsString* cons = i::ConsString::cast(*string); - CHECK_EQ(0, cons->second()->length()); - CHECK(cons->first()->IsTwoByteRepresentation()); + // If the cons string has been short-circuited, skip the following checks. + if (!string.is_identical_to(flat_string)) { + // At this point, we should have a Cons string which is flat and ASCII, + // with a first half that is a two-byte string (although it only contains + // ASCII characters). This is a valid sequence of steps, and it can happen + // in real pages. + CHECK(string->IsOneByteRepresentation()); + i::ConsString* cons = i::ConsString::cast(*string); + CHECK_EQ(0, cons->second()->length()); + CHECK(cons->first()->IsTwoByteRepresentation()); + } // Check that some string operations work. diff --git a/deps/v8/test/cctest/test-cpu-profiler.cc b/deps/v8/test/cctest/test-cpu-profiler.cc index 04d7ecb4f..0bf80003f 100644 --- a/deps/v8/test/cctest/test-cpu-profiler.cc +++ b/deps/v8/test/cctest/test-cpu-profiler.cc @@ -300,100 +300,102 @@ TEST(DeleteAllCpuProfiles) { TEST(DeleteCpuProfile) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler(); - CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount()); + CHECK_EQ(0, cpu_profiler->GetProfileCount()); v8::Local<v8::String> name1 = v8::String::New("1"); - v8::CpuProfiler::StartProfiling(name1); - const v8::CpuProfile* p1 = v8::CpuProfiler::StopProfiling(name1); + cpu_profiler->StartCpuProfiling(name1); + const v8::CpuProfile* p1 = cpu_profiler->StopCpuProfiling(name1); CHECK_NE(NULL, p1); - CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount()); + CHECK_EQ(1, cpu_profiler->GetProfileCount()); unsigned uid1 = p1->GetUid(); - CHECK_EQ(p1, v8::CpuProfiler::FindProfile(uid1)); + CHECK_EQ(p1, cpu_profiler->FindCpuProfile(uid1)); const_cast<v8::CpuProfile*>(p1)->Delete(); - CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount()); - CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1)); + CHECK_EQ(0, cpu_profiler->GetProfileCount()); + CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid1)); v8::Local<v8::String> name2 = v8::String::New("2"); - v8::CpuProfiler::StartProfiling(name2); - const v8::CpuProfile* p2 = v8::CpuProfiler::StopProfiling(name2); + cpu_profiler->StartCpuProfiling(name2); + const v8::CpuProfile* p2 = cpu_profiler->StopCpuProfiling(name2); CHECK_NE(NULL, p2); - CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount()); + CHECK_EQ(1, cpu_profiler->GetProfileCount()); unsigned uid2 = p2->GetUid(); CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2)); - CHECK_EQ(p2, v8::CpuProfiler::FindProfile(uid2)); - CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1)); + CHECK_EQ(p2, cpu_profiler->FindCpuProfile(uid2)); + CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid1)); v8::Local<v8::String> name3 = v8::String::New("3"); - v8::CpuProfiler::StartProfiling(name3); - const v8::CpuProfile* p3 = v8::CpuProfiler::StopProfiling(name3); + cpu_profiler->StartCpuProfiling(name3); + const v8::CpuProfile* p3 = cpu_profiler->StopCpuProfiling(name3); CHECK_NE(NULL, p3); - CHECK_EQ(2, v8::CpuProfiler::GetProfilesCount()); + CHECK_EQ(2, cpu_profiler->GetProfileCount()); unsigned uid3 = p3->GetUid(); CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3)); - CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3)); - CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1)); + CHECK_EQ(p3, cpu_profiler->FindCpuProfile(uid3)); + CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid1)); const_cast<v8::CpuProfile*>(p2)->Delete(); - CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount()); - CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2)); - CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3)); + CHECK_EQ(1, cpu_profiler->GetProfileCount()); + CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid2)); + CHECK_EQ(p3, cpu_profiler->FindCpuProfile(uid3)); const_cast<v8::CpuProfile*>(p3)->Delete(); - CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount()); - CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid3)); - CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2)); - CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1)); + CHECK_EQ(0, cpu_profiler->GetProfileCount()); + CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid3)); + CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid2)); + CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid1)); } TEST(DeleteCpuProfileDifferentTokens) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler(); - CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount()); + CHECK_EQ(0, cpu_profiler->GetProfileCount()); v8::Local<v8::String> name1 = v8::String::New("1"); - v8::CpuProfiler::StartProfiling(name1); - const v8::CpuProfile* p1 = v8::CpuProfiler::StopProfiling(name1); + cpu_profiler->StartCpuProfiling(name1); + const v8::CpuProfile* p1 = cpu_profiler->StopCpuProfiling(name1); CHECK_NE(NULL, p1); - CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount()); + CHECK_EQ(1, cpu_profiler->GetProfileCount()); unsigned uid1 = p1->GetUid(); - CHECK_EQ(p1, v8::CpuProfiler::FindProfile(uid1)); + CHECK_EQ(p1, cpu_profiler->FindCpuProfile(uid1)); v8::Local<v8::String> token1 = v8::String::New("token1"); - const v8::CpuProfile* p1_t1 = v8::CpuProfiler::FindProfile(uid1, token1); + const v8::CpuProfile* p1_t1 = cpu_profiler->FindCpuProfile(uid1, token1); CHECK_NE(NULL, p1_t1); CHECK_NE(p1, p1_t1); - CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount()); + CHECK_EQ(1, cpu_profiler->GetProfileCount()); const_cast<v8::CpuProfile*>(p1)->Delete(); - CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount()); - CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1)); - CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1, token1)); + CHECK_EQ(0, cpu_profiler->GetProfileCount()); + CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid1)); + CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid1, token1)); const_cast<v8::CpuProfile*>(p1_t1)->Delete(); - CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount()); + CHECK_EQ(0, cpu_profiler->GetProfileCount()); v8::Local<v8::String> name2 = v8::String::New("2"); - v8::CpuProfiler::StartProfiling(name2); + cpu_profiler->StartCpuProfiling(name2); v8::Local<v8::String> token2 = v8::String::New("token2"); - const v8::CpuProfile* p2_t2 = v8::CpuProfiler::StopProfiling(name2, token2); + const v8::CpuProfile* p2_t2 = cpu_profiler->StopCpuProfiling(name2, token2); CHECK_NE(NULL, p2_t2); - CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount()); + CHECK_EQ(1, cpu_profiler->GetProfileCount()); unsigned uid2 = p2_t2->GetUid(); CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2)); - const v8::CpuProfile* p2 = v8::CpuProfiler::FindProfile(uid2); + const v8::CpuProfile* p2 = cpu_profiler->FindCpuProfile(uid2); CHECK_NE(p2_t2, p2); v8::Local<v8::String> name3 = v8::String::New("3"); - v8::CpuProfiler::StartProfiling(name3); - const v8::CpuProfile* p3 = v8::CpuProfiler::StopProfiling(name3); + cpu_profiler->StartCpuProfiling(name3); + const v8::CpuProfile* p3 = cpu_profiler->StopCpuProfiling(name3); CHECK_NE(NULL, p3); - CHECK_EQ(2, v8::CpuProfiler::GetProfilesCount()); + CHECK_EQ(2, cpu_profiler->GetProfileCount()); unsigned uid3 = p3->GetUid(); CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3)); - CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3)); + CHECK_EQ(p3, cpu_profiler->FindCpuProfile(uid3)); const_cast<v8::CpuProfile*>(p2_t2)->Delete(); - CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount()); - CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2)); - CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3)); + CHECK_EQ(1, cpu_profiler->GetProfileCount()); + CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid2)); + CHECK_EQ(p3, cpu_profiler->FindCpuProfile(uid3)); const_cast<v8::CpuProfile*>(p2)->Delete(); - CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount()); - CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2)); - CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3)); + CHECK_EQ(1, cpu_profiler->GetProfileCount()); + CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid2)); + CHECK_EQ(p3, cpu_profiler->FindCpuProfile(uid3)); const_cast<v8::CpuProfile*>(p3)->Delete(); - CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount()); - CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid3)); + CHECK_EQ(0, cpu_profiler->GetProfileCount()); + CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid3)); } diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc index 263ad0277..a536f30b5 100644 --- a/deps/v8/test/cctest/test-heap-profiler.cc +++ b/deps/v8/test/cctest/test-heap-profiler.cc @@ -129,6 +129,7 @@ static bool HasString(const v8::HeapGraphNode* node, const char* contents) { TEST(HeapSnapshot) { LocalContext env2; v8::HandleScope scope(env2->GetIsolate()); + v8::HeapProfiler* heap_profiler = env2->GetIsolate()->GetHeapProfiler(); CompileRun( "function A2() {}\n" @@ -138,7 +139,7 @@ TEST(HeapSnapshot) { "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n" "var c2 = new C2(a2);"); const v8::HeapSnapshot* snapshot_env2 = - v8::HeapProfiler::TakeSnapshot(v8_str("env2")); + heap_profiler->TakeHeapSnapshot(v8_str("env2")); const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2); // Verify, that JS global object of env2 has '..2' properties. @@ -163,6 +164,7 @@ TEST(HeapSnapshot) { TEST(HeapSnapshotObjectSizes) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); // -a-> X1 --a // x -b-> X2 <-| @@ -172,7 +174,7 @@ TEST(HeapSnapshotObjectSizes) { "dummy = new X();\n" "(function() { x.a.a = x.b; })();"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("sizes")); + heap_profiler->TakeHeapSnapshot(v8_str("sizes")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* x = GetProperty(global, v8::HeapGraphEdge::kProperty, "x"); @@ -194,12 +196,13 @@ TEST(HeapSnapshotObjectSizes) { TEST(BoundFunctionInSnapshot) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun( "function myFunction(a, b) { this.a = a; this.b = b; }\n" "function AAAAA() {}\n" "boundFunction = myFunction.bind(new AAAAA(), 20, new Number(12)); \n"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("sizes")); + heap_profiler->TakeHeapSnapshot(v8_str("sizes")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* f = GetProperty(global, v8::HeapGraphEdge::kProperty, "boundFunction"); @@ -231,12 +234,13 @@ TEST(BoundFunctionInSnapshot) { TEST(HeapSnapshotEntryChildren) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun( "function A() { }\n" "a = new A;"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("children")); + heap_profiler->TakeHeapSnapshot(v8_str("children")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); for (int i = 0, count = global->GetChildrenCount(); i < count; ++i) { const v8::HeapGraphEdge* prop = global->GetChild(i); @@ -255,6 +259,7 @@ TEST(HeapSnapshotEntryChildren) { TEST(HeapSnapshotCodeObjects) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun( "function lazy(x) { return x - 1; }\n" @@ -262,7 +267,7 @@ TEST(HeapSnapshotCodeObjects) { "var anonymous = (function() { return function() { return 0; } })();\n" "compiled(1)"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("code")); + heap_profiler->TakeHeapSnapshot(v8_str("code")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* compiled = @@ -320,11 +325,12 @@ TEST(HeapSnapshotCodeObjects) { TEST(HeapSnapshotHeapNumbers) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun( "a = 1; // a is Smi\n" "b = 2.5; // b is HeapNumber"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("numbers")); + heap_profiler->TakeHeapSnapshot(v8_str("numbers")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kProperty, "a")); const v8::HeapGraphNode* b = @@ -336,6 +342,7 @@ TEST(HeapSnapshotHeapNumbers) { TEST(HeapSnapshotSlicedString) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun( "parent_string = \"123456789.123456789.123456789.123456789.123456789." "123456789.123456789.123456789.123456789.123456789." @@ -343,7 +350,7 @@ TEST(HeapSnapshotSlicedString) { "123456789.123456789.123456789.123456789.123456789.\";" "child_string = parent_string.slice(100);"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("strings")); + heap_profiler->TakeHeapSnapshot(v8_str("strings")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* parent_string = GetProperty(global, v8::HeapGraphEdge::kProperty, "parent_string"); @@ -357,7 +364,8 @@ TEST(HeapSnapshotSlicedString) { } TEST(HeapSnapshotInternalReferences) { - v8::HandleScope scope(v8::Isolate::GetCurrent()); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); global_template->SetInternalFieldCount(2); LocalContext env(NULL, global_template); @@ -367,8 +375,9 @@ TEST(HeapSnapshotInternalReferences) { v8::Local<v8::Object> obj = v8::Object::New(); global->SetInternalField(0, v8_num(17)); global->SetInternalField(1, obj); + v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler(); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("internals")); + heap_profiler->TakeHeapSnapshot(v8_str("internals")); const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot); // The first reference will not present, because it's a Smi. CHECK_EQ(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "0")); @@ -388,6 +397,7 @@ TEST(HeapSnapshotInternalReferences) { TEST(HeapSnapshotAddressReuse) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun( "function A() {}\n" @@ -395,7 +405,7 @@ TEST(HeapSnapshotAddressReuse) { "for (var i = 0; i < 10000; ++i)\n" " a[i] = new A();\n"); const v8::HeapSnapshot* snapshot1 = - v8::HeapProfiler::TakeSnapshot(v8_str("snapshot1")); + heap_profiler->TakeHeapSnapshot(v8_str("snapshot1")); v8::SnapshotObjectId maxId1 = snapshot1->GetMaxSnapshotJSObjectId(); CompileRun( @@ -404,7 +414,7 @@ TEST(HeapSnapshotAddressReuse) { HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); const v8::HeapSnapshot* snapshot2 = - v8::HeapProfiler::TakeSnapshot(v8_str("snapshot2")); + heap_profiler->TakeHeapSnapshot(v8_str("snapshot2")); const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2); const v8::HeapGraphNode* array_node = @@ -426,6 +436,7 @@ TEST(HeapSnapshotAddressReuse) { TEST(HeapEntryIdsAndArrayShift) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun( "function AnObject() {\n" @@ -436,7 +447,7 @@ TEST(HeapEntryIdsAndArrayShift) { "for (var i = 0; i < 10; ++i)\n" " a.push(new AnObject());\n"); const v8::HeapSnapshot* snapshot1 = - v8::HeapProfiler::TakeSnapshot(v8_str("s1")); + heap_profiler->TakeHeapSnapshot(v8_str("s1")); CompileRun( "for (var i = 0; i < 1; ++i)\n" @@ -445,7 +456,7 @@ TEST(HeapEntryIdsAndArrayShift) { HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); const v8::HeapSnapshot* snapshot2 = - v8::HeapProfiler::TakeSnapshot(v8_str("s2")); + heap_profiler->TakeHeapSnapshot(v8_str("s2")); const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1); const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2); @@ -472,6 +483,7 @@ TEST(HeapEntryIdsAndArrayShift) { TEST(HeapEntryIdsAndGC) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun( "function A() {}\n" @@ -481,12 +493,12 @@ TEST(HeapEntryIdsAndGC) { v8::Local<v8::String> s1_str = v8_str("s1"); v8::Local<v8::String> s2_str = v8_str("s2"); const v8::HeapSnapshot* snapshot1 = - v8::HeapProfiler::TakeSnapshot(s1_str); + heap_profiler->TakeHeapSnapshot(s1_str); HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); const v8::HeapSnapshot* snapshot2 = - v8::HeapProfiler::TakeSnapshot(s2_str); + heap_profiler->TakeHeapSnapshot(s2_str); CHECK_GT(snapshot1->GetMaxSnapshotJSObjectId(), 7000); CHECK(snapshot1->GetMaxSnapshotJSObjectId() <= @@ -534,8 +546,9 @@ TEST(HeapEntryIdsAndGC) { TEST(HeapSnapshotRootPreservedAfterSorting) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("s")); + heap_profiler->TakeHeapSnapshot(v8_str("s")); const v8::HeapGraphNode* root1 = snapshot->GetRoot(); const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>( snapshot))->GetSortedEntriesList(); @@ -592,6 +605,7 @@ class AsciiResource: public v8::String::ExternalAsciiStringResource { TEST(HeapSnapshotJSONSerialization) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); #define STRING_LITERAL_FOR_TEST \ "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\"" @@ -601,7 +615,7 @@ TEST(HeapSnapshotJSONSerialization) { "var a = new A(" STRING_LITERAL_FOR_TEST ");\n" "var b = new B(a);"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("json")); + heap_profiler->TakeHeapSnapshot(v8_str("json")); TestJSONStream stream; snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON); CHECK_GT(stream.size(), 0); @@ -694,8 +708,9 @@ TEST(HeapSnapshotJSONSerialization) { TEST(HeapSnapshotJSONSerializationAborting) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("abort")); + heap_profiler->TakeHeapSnapshot(v8_str("abort")); TestJSONStream stream(5); snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON); CHECK_GT(stream.size(), 0); @@ -761,10 +776,10 @@ class TestStatsStream : public v8::OutputStream { } // namespace static TestStatsStream GetHeapStatsUpdate( + v8::HeapProfiler* heap_profiler, v8::SnapshotObjectId* object_id = NULL) { TestStatsStream stream; - v8::SnapshotObjectId last_seen_id = - v8::HeapProfiler::PushHeapObjectsStats(&stream); + v8::SnapshotObjectId last_seen_id = heap_profiler->GetHeapStats(&stream); if (object_id) *object_id = last_seen_id; CHECK_EQ(1, stream.eos_signaled()); @@ -775,8 +790,9 @@ static TestStatsStream GetHeapStatsUpdate( TEST(HeapSnapshotObjectsStats) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); - v8::HeapProfiler::StartHeapObjectsTracking(); + heap_profiler->StartTrackingHeapObjects(); // We have to call GC 6 times. In other case the garbage will be // the reason of flakiness. for (int i = 0; i < 6; ++i) { @@ -786,7 +802,8 @@ TEST(HeapSnapshotObjectsStats) { v8::SnapshotObjectId initial_id; { // Single chunk of data expected in update. Initial data. - TestStatsStream stats_update = GetHeapStatsUpdate(&initial_id); + TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler, + &initial_id); CHECK_EQ(1, stats_update.intervals_count()); CHECK_EQ(1, stats_update.updates_written()); CHECK_LT(0, stats_update.entries_size()); @@ -795,7 +812,7 @@ TEST(HeapSnapshotObjectsStats) { // No data expected in update because nothing has happened. v8::SnapshotObjectId same_id; - CHECK_EQ(0, GetHeapStatsUpdate(&same_id).updates_written()); + CHECK_EQ(0, GetHeapStatsUpdate(heap_profiler, &same_id).updates_written()); CHECK_EQ_SNAPSHOT_OBJECT_ID(initial_id, same_id); { @@ -804,7 +821,8 @@ TEST(HeapSnapshotObjectsStats) { v8_str("string1"); { // Single chunk of data with one new entry expected in update. - TestStatsStream stats_update = GetHeapStatsUpdate(&additional_string_id); + TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler, + &additional_string_id); CHECK_LT(same_id, additional_string_id); CHECK_EQ(1, stats_update.intervals_count()); CHECK_EQ(1, stats_update.updates_written()); @@ -815,7 +833,7 @@ TEST(HeapSnapshotObjectsStats) { // No data expected in update because nothing happened. v8::SnapshotObjectId last_id; - CHECK_EQ(0, GetHeapStatsUpdate(&last_id).updates_written()); + CHECK_EQ(0, GetHeapStatsUpdate(heap_profiler, &last_id).updates_written()); CHECK_EQ_SNAPSHOT_OBJECT_ID(additional_string_id, last_id); { @@ -830,7 +848,7 @@ TEST(HeapSnapshotObjectsStats) { { // Single chunk of data with three new entries expected in update. - TestStatsStream stats_update = GetHeapStatsUpdate(); + TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler); CHECK_EQ(1, stats_update.intervals_count()); CHECK_EQ(1, stats_update.updates_written()); CHECK_LT(0, entries_size = stats_update.entries_size()); @@ -841,7 +859,7 @@ TEST(HeapSnapshotObjectsStats) { { // Single chunk of data with two left entries expected in update. - TestStatsStream stats_update = GetHeapStatsUpdate(); + TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler); CHECK_EQ(1, stats_update.intervals_count()); CHECK_EQ(1, stats_update.updates_written()); CHECK_GT(entries_size, stats_update.entries_size()); @@ -853,7 +871,7 @@ TEST(HeapSnapshotObjectsStats) { { // Single chunk of data with 0 left entries expected in update. - TestStatsStream stats_update = GetHeapStatsUpdate(); + TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler); CHECK_EQ(1, stats_update.intervals_count()); CHECK_EQ(1, stats_update.updates_written()); CHECK_EQ(0, stats_update.entries_size()); @@ -864,7 +882,7 @@ TEST(HeapSnapshotObjectsStats) { } { // Single chunk of data with 0 left entries expected in update. - TestStatsStream stats_update = GetHeapStatsUpdate(); + TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler); CHECK_EQ(1, stats_update.intervals_count()); CHECK_EQ(1, stats_update.updates_written()); CHECK_EQ(0, stats_update.entries_size()); @@ -881,7 +899,7 @@ TEST(HeapSnapshotObjectsStats) { uint32_t entries_size; { // Single chunk of data with 2 entries expected in update. - TestStatsStream stats_update = GetHeapStatsUpdate(); + TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler); CHECK_EQ(1, stats_update.intervals_count()); CHECK_EQ(1, stats_update.updates_written()); CHECK_LT(0, entries_size = stats_update.entries_size()); @@ -895,7 +913,7 @@ TEST(HeapSnapshotObjectsStats) { { // Single chunk of data with 1 entry expected in update. - TestStatsStream stats_update = GetHeapStatsUpdate(); + TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler); CHECK_EQ(1, stats_update.intervals_count()); // The first interval was changed because old buffer was collected. // The second interval was changed because new buffer was allocated. @@ -905,7 +923,7 @@ TEST(HeapSnapshotObjectsStats) { CHECK_EQ(8, stats_update.first_interval_index()); } - v8::HeapProfiler::StopHeapObjectsTracking(); + heap_profiler->StopTrackingHeapObjects(); } @@ -928,9 +946,10 @@ static void CheckChildrenIds(const v8::HeapSnapshot* snapshot, TEST(HeapSnapshotGetNodeById) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("id")); + heap_profiler->TakeHeapSnapshot(v8_str("id")); const v8::HeapGraphNode* root = snapshot->GetRoot(); CheckChildrenIds(snapshot, root, 0, 3); // Check a big id, which should not exist yet. @@ -941,9 +960,10 @@ TEST(HeapSnapshotGetNodeById) { TEST(HeapSnapshotGetSnapshotObjectId) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("globalObject = {};\n"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("get_snapshot_object_id")); + heap_profiler->TakeHeapSnapshot(v8_str("get_snapshot_object_id")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* global_object = GetProperty(global, v8::HeapGraphEdge::kProperty, "globalObject"); @@ -954,8 +974,7 @@ TEST(HeapSnapshotGetSnapshotObjectId) { CHECK(!globalObjectHandle.IsEmpty()); CHECK(globalObjectHandle->IsObject()); - v8::SnapshotObjectId id = - v8::HeapProfiler::GetSnapshotObjectId(globalObjectHandle); + v8::SnapshotObjectId id = heap_profiler->GetObjectId(globalObjectHandle); CHECK_NE(static_cast<int>(v8::HeapProfiler::kUnknownObjectId), id); CHECK_EQ(static_cast<int>(id), global_object->GetId()); @@ -965,9 +984,10 @@ TEST(HeapSnapshotGetSnapshotObjectId) { TEST(HeapSnapshotUnknownSnapshotObjectId) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("globalObject = {};\n"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("unknown_object_id")); + heap_profiler->TakeHeapSnapshot(v8_str("unknown_object_id")); const v8::HeapGraphNode* node = snapshot->GetNodeById(v8::HeapProfiler::kUnknownObjectId); CHECK_EQ(NULL, node); @@ -999,23 +1019,22 @@ TEST(TakeHeapSnapshotAborting) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); - const int snapshots_count = v8::HeapProfiler::GetSnapshotsCount(); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); + const int snapshots_count = heap_profiler->GetSnapshotCount(); TestActivityControl aborting_control(1); const v8::HeapSnapshot* no_snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("abort"), - v8::HeapSnapshot::kFull, + heap_profiler->TakeHeapSnapshot(v8_str("abort"), &aborting_control); CHECK_EQ(NULL, no_snapshot); - CHECK_EQ(snapshots_count, v8::HeapProfiler::GetSnapshotsCount()); + CHECK_EQ(snapshots_count, heap_profiler->GetSnapshotCount()); CHECK_GT(aborting_control.total(), aborting_control.done()); TestActivityControl control(-1); // Don't abort. const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("full"), - v8::HeapSnapshot::kFull, + heap_profiler->TakeHeapSnapshot(v8_str("full"), &control); CHECK_NE(NULL, snapshot); - CHECK_EQ(snapshots_count + 1, v8::HeapProfiler::GetSnapshotsCount()); + CHECK_EQ(snapshots_count + 1, heap_profiler->GetSnapshotCount()); CHECK_EQ(control.total(), control.done()); CHECK_GT(control.total(), 0); } @@ -1109,10 +1128,11 @@ TEST(HeapSnapshotRetainedObjectInfo) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); + v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler(); - v8::HeapProfiler::DefineWrapperClass( + heap_profiler->SetWrapperClassInfoProvider( 1, TestRetainedObjectInfo::WrapperInfoCallback); - v8::HeapProfiler::DefineWrapperClass( + heap_profiler->SetWrapperClassInfoProvider( 2, TestRetainedObjectInfo::WrapperInfoCallback); v8::Persistent<v8::String> p_AAA = v8::Persistent<v8::String>::New(isolate, v8_str("AAA")); @@ -1125,7 +1145,7 @@ TEST(HeapSnapshotRetainedObjectInfo) { p_CCC.SetWrapperClassId(isolate, 2); CHECK_EQ(0, TestRetainedObjectInfo::instances.length()); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("retained")); + heap_profiler->TakeHeapSnapshot(v8_str("retained")); CHECK_EQ(3, TestRetainedObjectInfo::instances.length()); for (int i = 0; i < TestRetainedObjectInfo::instances.length(); ++i) { @@ -1205,12 +1225,13 @@ GraphWithImplicitRefs* GraphWithImplicitRefs::instance_ = NULL; TEST(HeapSnapshotImplicitReferences) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); GraphWithImplicitRefs graph(&env); v8::V8::AddGCPrologueCallback(&GraphWithImplicitRefs::gcPrologue); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("implicit_refs")); + heap_profiler->TakeHeapSnapshot(v8_str("implicit_refs")); const v8::HeapGraphNode* global_object = GetGlobalObject(snapshot); const v8::HeapGraphNode* obj0 = GetProperty( @@ -1237,58 +1258,60 @@ TEST(HeapSnapshotImplicitReferences) { TEST(DeleteAllHeapSnapshots) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); - - CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount()); - v8::HeapProfiler::DeleteAllSnapshots(); - CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount()); - CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8_str("1"))); - CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount()); - v8::HeapProfiler::DeleteAllSnapshots(); - CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount()); - CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8_str("1"))); - CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8_str("2"))); - CHECK_EQ(2, v8::HeapProfiler::GetSnapshotsCount()); - v8::HeapProfiler::DeleteAllSnapshots(); - CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); + + CHECK_EQ(0, heap_profiler->GetSnapshotCount()); + heap_profiler->DeleteAllHeapSnapshots(); + CHECK_EQ(0, heap_profiler->GetSnapshotCount()); + CHECK_NE(NULL, heap_profiler->TakeHeapSnapshot(v8_str("1"))); + CHECK_EQ(1, heap_profiler->GetSnapshotCount()); + heap_profiler->DeleteAllHeapSnapshots(); + CHECK_EQ(0, heap_profiler->GetSnapshotCount()); + CHECK_NE(NULL, heap_profiler->TakeHeapSnapshot(v8_str("1"))); + CHECK_NE(NULL, heap_profiler->TakeHeapSnapshot(v8_str("2"))); + CHECK_EQ(2, heap_profiler->GetSnapshotCount()); + heap_profiler->DeleteAllHeapSnapshots(); + CHECK_EQ(0, heap_profiler->GetSnapshotCount()); } TEST(DeleteHeapSnapshot) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); - CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount()); + CHECK_EQ(0, heap_profiler->GetSnapshotCount()); const v8::HeapSnapshot* s1 = - v8::HeapProfiler::TakeSnapshot(v8_str("1")); + heap_profiler->TakeHeapSnapshot(v8_str("1")); CHECK_NE(NULL, s1); - CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount()); + CHECK_EQ(1, heap_profiler->GetSnapshotCount()); unsigned uid1 = s1->GetUid(); - CHECK_EQ(s1, v8::HeapProfiler::FindSnapshot(uid1)); + CHECK_EQ(s1, heap_profiler->FindHeapSnapshot(uid1)); const_cast<v8::HeapSnapshot*>(s1)->Delete(); - CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount()); - CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid1)); + CHECK_EQ(0, heap_profiler->GetSnapshotCount()); + CHECK_EQ(NULL, heap_profiler->FindHeapSnapshot(uid1)); const v8::HeapSnapshot* s2 = - v8::HeapProfiler::TakeSnapshot(v8_str("2")); + heap_profiler->TakeHeapSnapshot(v8_str("2")); CHECK_NE(NULL, s2); - CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount()); + CHECK_EQ(1, heap_profiler->GetSnapshotCount()); unsigned uid2 = s2->GetUid(); CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2)); - CHECK_EQ(s2, v8::HeapProfiler::FindSnapshot(uid2)); + CHECK_EQ(s2, heap_profiler->FindHeapSnapshot(uid2)); const v8::HeapSnapshot* s3 = - v8::HeapProfiler::TakeSnapshot(v8_str("3")); + heap_profiler->TakeHeapSnapshot(v8_str("3")); CHECK_NE(NULL, s3); - CHECK_EQ(2, v8::HeapProfiler::GetSnapshotsCount()); + CHECK_EQ(2, heap_profiler->GetSnapshotCount()); unsigned uid3 = s3->GetUid(); CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3)); - CHECK_EQ(s3, v8::HeapProfiler::FindSnapshot(uid3)); + CHECK_EQ(s3, heap_profiler->FindHeapSnapshot(uid3)); const_cast<v8::HeapSnapshot*>(s2)->Delete(); - CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount()); - CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid2)); - CHECK_EQ(s3, v8::HeapProfiler::FindSnapshot(uid3)); + CHECK_EQ(1, heap_profiler->GetSnapshotCount()); + CHECK_EQ(NULL, heap_profiler->FindHeapSnapshot(uid2)); + CHECK_EQ(s3, heap_profiler->FindHeapSnapshot(uid3)); const_cast<v8::HeapSnapshot*>(s3)->Delete(); - CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount()); - CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid3)); + CHECK_EQ(0, heap_profiler->GetSnapshotCount()); + CHECK_EQ(NULL, heap_profiler->FindHeapSnapshot(uid3)); } @@ -1302,13 +1325,13 @@ class NameResolver : public v8::HeapProfiler::ObjectNameResolver { TEST(GlobalObjectName) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("document = { URL:\"abcdefgh\" };"); NameResolver name_resolver; const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("document"), - v8::HeapSnapshot::kFull, + heap_profiler->TakeHeapSnapshot(v8_str("document"), NULL, &name_resolver); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); @@ -1322,13 +1345,14 @@ TEST(GlobalObjectName) { TEST(NoHandleLeaks) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("document = { URL:\"abcdefgh\" };"); v8::Handle<v8::String> name(v8_str("leakz")); i::Isolate* isolate = i::Isolate::Current(); int count_before = i::HandleScope::NumberOfHandles(isolate); - v8::HeapProfiler::TakeSnapshot(name); + heap_profiler->TakeHeapSnapshot(name); int count_after = i::HandleScope::NumberOfHandles(isolate); CHECK_EQ(count_before, count_after); } @@ -1337,8 +1361,9 @@ TEST(NoHandleLeaks) { TEST(NodesIteration) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("iteration")); + heap_profiler->TakeHeapSnapshot(v8_str("iteration")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK_NE(NULL, global); // Verify that we can find this object by iteration. @@ -1355,10 +1380,11 @@ TEST(NodesIteration) { TEST(GetHeapValue) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("a = { s_prop: \'value\', n_prop: 0.1 };"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("value")); + heap_profiler->TakeHeapSnapshot(v8_str("value")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK(global->GetHeapValue()->IsObject()); v8::Local<v8::Object> js_global = @@ -1385,13 +1411,14 @@ TEST(GetHeapValue) { TEST(GetHeapValueForDeletedObject) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); // It is impossible to delete a global property, so we are about to delete a // property of the "a" object. Also, the "p" object can't be an empty one // because the empty object is static and isn't actually deleted. CompileRun("a = { p: { r: {} } };"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("snapshot")); + heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* obj = GetProperty( global, v8::HeapGraphEdge::kProperty, "a"); @@ -1467,6 +1494,7 @@ TEST(GetConstructorName) { TEST(FastCaseGetter) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("var obj1 = {};\n" "obj1.__defineGetter__('propWithGetter', function Y() {\n" @@ -1476,7 +1504,7 @@ TEST(FastCaseGetter) { " return this.value_ = value;\n" "});\n"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("fastCaseGetter")); + heap_profiler->TakeHeapSnapshot(v8_str("fastCaseGetter")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK_NE(NULL, global); @@ -1494,12 +1522,13 @@ TEST(FastCaseGetter) { TEST(HiddenPropertiesFastCase) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun( "function C(x) { this.a = this; this.b = x; }\n" "c = new C(2012);\n"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("HiddenPropertiesFastCase1")); + heap_profiler->TakeHeapSnapshot(v8_str("HiddenPropertiesFastCase1")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* c = GetProperty(global, v8::HeapGraphEdge::kProperty, "c"); @@ -1512,7 +1541,7 @@ TEST(HiddenPropertiesFastCase) { CHECK(!cHandle.IsEmpty() && cHandle->IsObject()); cHandle->ToObject()->SetHiddenValue(v8_str("key"), v8_str("val")); - snapshot = v8::HeapProfiler::TakeSnapshot( + snapshot = heap_profiler->TakeHeapSnapshot( v8_str("HiddenPropertiesFastCase2")); global = GetGlobalObject(snapshot); c = GetProperty(global, v8::HeapGraphEdge::kProperty, "c"); @@ -1532,8 +1561,10 @@ bool HasWeakEdge(const v8::HeapGraphNode* node) { bool HasWeakGlobalHandle() { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler(); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("weaks")); + heap_profiler->TakeHeapSnapshot(v8_str("weaks")); const v8::HeapGraphNode* gc_roots = GetNode( snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(GC roots)"); CHECK_NE(NULL, gc_roots); @@ -1568,9 +1599,10 @@ TEST(WeakGlobalHandle) { TEST(WeakNativeContextRefs) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("weaks")); + heap_profiler->TakeHeapSnapshot(v8_str("weaks")); const v8::HeapGraphNode* gc_roots = GetNode( snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(GC roots)"); CHECK_NE(NULL, gc_roots); @@ -1587,11 +1619,12 @@ TEST(WeakNativeContextRefs) { TEST(SfiAndJsFunctionWeakRefs) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun( "fun = (function (x) { return function () { return x + 1; } })(1);"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("fun")); + heap_profiler->TakeHeapSnapshot(v8_str("fun")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK_NE(NULL, global); const v8::HeapGraphNode* fun = @@ -1607,11 +1640,12 @@ TEST(SfiAndJsFunctionWeakRefs) { TEST(NoDebugObjectInSnapshot) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); v8::internal::Isolate::Current()->debug()->Load(); CompileRun("foo = {};"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("snapshot")); + heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); const v8::HeapGraphNode* root = snapshot->GetRoot(); int globals_count = 0; for (int i = 0; i < root->GetChildrenCount(); ++i) { @@ -1667,10 +1701,11 @@ TEST(PersistentHandleCount) { TEST(AllStrongGcRootsHaveNames) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("foo = {};"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("snapshot")); + heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); const v8::HeapGraphNode* gc_roots = GetNode( snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(GC roots)"); CHECK_NE(NULL, gc_roots); @@ -1689,9 +1724,10 @@ TEST(AllStrongGcRootsHaveNames) { TEST(NoRefsToNonEssentialEntries) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("global_object = {};\n"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("snapshot")); + heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* global_object = GetProperty(global, v8::HeapGraphEdge::kProperty, "global_object"); @@ -1708,9 +1744,10 @@ TEST(NoRefsToNonEssentialEntries) { TEST(MapHasDescriptorsAndTransitions) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("obj = { a: 10 };\n"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("snapshot")); + heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* global_object = GetProperty(global, v8::HeapGraphEdge::kProperty, "obj"); @@ -1729,8 +1766,9 @@ TEST(MapHasDescriptorsAndTransitions) { TEST(ManyLocalsInSharedContext) { - v8::HandleScope scope; LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); int num_objects = 6000; CompileRun( "var n = 6000;" @@ -1747,7 +1785,7 @@ TEST(ManyLocalsInSharedContext) { "result.push('})()');" "var ok = eval(result.join('\\n'));"); const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("snapshot")); + heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK_NE(NULL, global); const v8::HeapGraphNode* ok_object = diff --git a/deps/v8/test/cctest/test-heap.cc b/deps/v8/test/cctest/test-heap.cc index a710385bf..d0bec935d 100644 --- a/deps/v8/test/cctest/test-heap.cc +++ b/deps/v8/test/cctest/test-heap.cc @@ -1240,6 +1240,7 @@ TEST(TestCodeFlushingIncrementalAbort) { // code flushing candidate. SimulateIncrementalMarking(); +#ifdef ENABLE_DEBUGGER_SUPPORT // Enable the debugger and add a breakpoint while incremental marking // is running so that incremental marking aborts and code flushing is // disabled. @@ -1247,6 +1248,7 @@ TEST(TestCodeFlushingIncrementalAbort) { Handle<Object> breakpoint_object(Smi::FromInt(0), isolate); isolate->debug()->SetBreakPoint(function, breakpoint_object, &position); isolate->debug()->ClearAllBreakPoints(); +#endif // ENABLE_DEBUGGER_SUPPORT // Force optimization now that code flushing is disabled. { v8::HandleScope scope(env->GetIsolate()); @@ -3010,8 +3012,10 @@ TEST(Regress173458) { // explicitly enqueued. SimulateIncrementalMarking(); +#ifdef ENABLE_DEBUGGER_SUPPORT // Now enable the debugger which in turn will disable code flushing. CHECK(isolate->debug()->Load()); +#endif // ENABLE_DEBUGGER_SUPPORT // This cycle will bust the heap and subsequent cycles will go ballistic. heap->CollectAllGarbage(Heap::kNoGCFlags); diff --git a/deps/v8/test/cctest/test-profile-generator.cc b/deps/v8/test/cctest/test-profile-generator.cc index 864229ee3..56b1788a8 100644 --- a/deps/v8/test/cctest/test-profile-generator.cc +++ b/deps/v8/test/cctest/test-profile-generator.cc @@ -830,20 +830,22 @@ v8::Handle<v8::FunctionTemplate> ProfilerExtension::GetNativeFunction( v8::Handle<v8::Value> ProfilerExtension::StartProfiling( const v8::Arguments& args) { + v8::CpuProfiler* cpu_profiler = args.GetIsolate()->GetCpuProfiler(); if (args.Length() > 0) - v8::CpuProfiler::StartProfiling(args[0].As<v8::String>()); + cpu_profiler->StartCpuProfiling(args[0].As<v8::String>()); else - v8::CpuProfiler::StartProfiling(v8::String::New("")); + cpu_profiler->StartCpuProfiling(v8::String::New("")); return v8::Undefined(); } v8::Handle<v8::Value> ProfilerExtension::StopProfiling( const v8::Arguments& args) { + v8::CpuProfiler* cpu_profiler = args.GetIsolate()->GetCpuProfiler(); if (args.Length() > 0) - v8::CpuProfiler::StopProfiling(args[0].As<v8::String>()); + cpu_profiler->StopCpuProfiling(args[0].As<v8::String>()); else - v8::CpuProfiler::StopProfiling(v8::String::New("")); + cpu_profiler->StopCpuProfiling(v8::String::New("")); return v8::Undefined(); } diff --git a/deps/v8/test/cctest/test-strings.cc b/deps/v8/test/cctest/test-strings.cc index f240e9314..9aebdb18f 100644 --- a/deps/v8/test/cctest/test-strings.cc +++ b/deps/v8/test/cctest/test-strings.cc @@ -1082,7 +1082,9 @@ TEST(SliceFromCons) { CHECK(parent->IsFlat()); CHECK(slice->IsSlicedString()); CHECK_EQ(SlicedString::cast(*slice)->parent(), - ConsString::cast(*parent)->first()); + // Parent could have been short-circuited. + parent->IsConsString() ? ConsString::cast(*parent)->first() + : *parent); CHECK(SlicedString::cast(*slice)->parent()->IsSeqString()); CHECK(slice->IsFlat()); } diff --git a/deps/v8/test/message/overwritten-builtins.out b/deps/v8/test/message/overwritten-builtins.out index 77d72c144..db31bbf08 100644 --- a/deps/v8/test/message/overwritten-builtins.out +++ b/deps/v8/test/message/overwritten-builtins.out @@ -30,3 +30,4 @@ undefined.x ^ TypeError: Cannot read property 'x' of undefined at *%(basename)s:31:10 + diff --git a/deps/v8/test/mjsunit/array-non-smi-length.js b/deps/v8/test/mjsunit/array-non-smi-length.js new file mode 100644 index 000000000..23a25ee79 --- /dev/null +++ b/deps/v8/test/mjsunit/array-non-smi-length.js @@ -0,0 +1,46 @@ +// 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. + +// Flags: --allow-natives-syntax + +function TestNonSmiArrayLength() { + function f(a) { + return a.length+1; + } + + var a = []; + a.length = 0xFFFF; + assertSame(0x10000, f(a)); + assertSame(0x10000, f(a)); + + %OptimizeFunctionOnNextCall(f); + a.length = 0xFFFFFFFF; + assertSame(0x100000000, f(a)); +} + +TestNonSmiArrayLength(); + diff --git a/deps/v8/test/mjsunit/array-shift.js b/deps/v8/test/mjsunit/array-shift.js index 3601cbbb8..ad742e12e 100644 --- a/deps/v8/test/mjsunit/array-shift.js +++ b/deps/v8/test/mjsunit/array-shift.js @@ -106,3 +106,17 @@ assertEquals(array[7], array_proto[7]); assertFalse(array.hasOwnProperty(7)); })(); + +// Check that non-enumerable elements are treated appropriately +(function() { + var array = [1, 2, 3]; + Object.defineProperty(array, '1', {enumerable: false}); + assertEquals(1, array.shift()); + assertEquals([2, 3], array); + + array = [1,,3]; + array.__proto__[1] = 2; + Object.defineProperty(array.__proto__, '1', {enumerable: false}); + assertEquals(1, array.shift()); + assertEquals([2, 3], array); +})(); diff --git a/deps/v8/test/mjsunit/array-splice.js b/deps/v8/test/mjsunit/array-splice.js index 0e307b5d3..be2b1064e 100644 --- a/deps/v8/test/mjsunit/array-splice.js +++ b/deps/v8/test/mjsunit/array-splice.js @@ -285,8 +285,8 @@ assertFalse(array.hasOwnProperty(15), "array.hasOwnProperty(15)"); assertFalse(array.hasOwnProperty(31), "array.hasOwnProperty(31)"); assertFalse(array.hasOwnProperty(63), "array.hasOwnProperty(63)"); - assertFalse(array.hasOwnProperty(2 << 32 - 1), - "array.hasOwnProperty(2 << 31 - 1)"); + assertFalse(array.hasOwnProperty(Math.pow(2, 32) - 2), + "array.hasOwnProperty(Math.pow(2, 32) - 2)"); } })(); @@ -333,8 +333,8 @@ assertFalse(array.hasOwnProperty(15), "array.hasOwnProperty(15)"); assertFalse(array.hasOwnProperty(31), "array.hasOwnProperty(31)"); assertFalse(array.hasOwnProperty(63), "array.hasOwnProperty(63)"); - assertFalse(array.hasOwnProperty(2 << 32 - 1), - "array.hasOwnProperty(2 << 31 - 1)"); + assertFalse(array.hasOwnProperty(Math.pow(2, 32) - 2), + "array.hasOwnProperty(Math.pow(2, 32) - 2)"); } })(); @@ -357,7 +357,7 @@ (function() { for (var i = 0; i < 7; i++) { try { - new Array((1 << 32) - 3).splice(-1, 0, 1, 2, 3, 4, 5); + new Array(Math.pow(2, 32) - 3).splice(-1, 0, 1, 2, 3, 4, 5); throw 'Should have thrown RangeError'; } catch (e) { assertTrue(e instanceof RangeError); diff --git a/deps/v8/test/mjsunit/array-unshift.js b/deps/v8/test/mjsunit/array-unshift.js index c4cc95cbb..0eb299a0c 100644 --- a/deps/v8/test/mjsunit/array-unshift.js +++ b/deps/v8/test/mjsunit/array-unshift.js @@ -194,7 +194,7 @@ (function() { for (var i = 0; i < 7; i++) { try { - new Array((1 << 32) - 3).unshift(1, 2, 3, 4, 5); + new Array(Math.pow(2, 32) - 3).unshift(1, 2, 3, 4, 5); throw 'Should have thrown RangeError'; } catch (e) { assertTrue(e instanceof RangeError); @@ -213,3 +213,18 @@ assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], a); } })(); + +// Check that non-enumerable elements are treated appropriately +(function() { + var array = [2, 3]; + Object.defineProperty(array, '1', {enumerable: false}); + array.unshift(1) + assertEquals([1, 2, 3], array); + + array = [2]; + array.length = 2; + array.__proto__[1] = 3; + Object.defineProperty(array.__proto__, '1', {enumerable: false}); + array.unshift(1); + assertEquals([1, 2, 3], array); +})(); diff --git a/deps/v8/test/mjsunit/compiler/rotate.js b/deps/v8/test/mjsunit/compiler/rotate.js index 1db1fb329..14fe9da3e 100644 --- a/deps/v8/test/mjsunit/compiler/rotate.js +++ b/deps/v8/test/mjsunit/compiler/rotate.js @@ -221,3 +221,4 @@ for (var i = 0; i <= 100; i++) { %OptimizeFunctionOnNextCall(ROR4); assertEquals(1 << ((i % 32)), ROR4(1, i)); } + diff --git a/deps/v8/test/mjsunit/debug-evaluate-locals.js b/deps/v8/test/mjsunit/debug-evaluate-locals.js index 61b6dd9bb..a68162d9b 100644 --- a/deps/v8/test/mjsunit/debug-evaluate-locals.js +++ b/deps/v8/test/mjsunit/debug-evaluate-locals.js @@ -36,19 +36,20 @@ exception = false; function h() { var a = 1; var b = 2; + var eval = 5; // Overriding eval should not break anything. debugger; // Breakpoint. } function checkFrame0(frame) { // Frame 0 (h) has normal variables a and b. var count = frame.localCount(); - assertEquals(2, count); + assertEquals(3, count); for (var i = 0; i < count; ++i) { var name = frame.localName(i); var value = frame.localValue(i).value(); if (name == 'a') { assertEquals(1, value); - } else { + } else if (name !='eval') { assertEquals('b', name); assertEquals(2, value); } @@ -115,16 +116,21 @@ function listener(event, exec_state, event_data, data) { // Evaluating a and b on frames 0, 1 and 2 produces 1, 2, 3, 4, 5 and 6. assertEquals(1, exec_state.frame(0).evaluate('a').value()); assertEquals(2, exec_state.frame(0).evaluate('b').value()); + assertEquals(5, exec_state.frame(0).evaluate('eval').value()); assertEquals(3, exec_state.frame(1).evaluate('a').value()); assertEquals(4, exec_state.frame(1).evaluate('b').value()); + assertEquals("function", + typeof exec_state.frame(1).evaluate('eval').value()); assertEquals(5, exec_state.frame(2).evaluate('a').value()); assertEquals(6, exec_state.frame(2).evaluate('b').value()); - + assertEquals("function", + typeof exec_state.frame(2).evaluate('eval').value()); // Indicate that all was processed. listenerComplete = true; } } catch (e) { exception = e + print("Caught something. " + e + " " + e.stack); }; }; @@ -133,6 +139,6 @@ Debug.setListener(listener); f(); -// Make sure that the debug event listener vas invoked. -assertTrue(listenerComplete); +// Make sure that the debug event listener was invoked. assertFalse(exception, "exception in listener") +assertTrue(listenerComplete); diff --git a/deps/v8/test/mjsunit/debug-liveedit-compile-error.js b/deps/v8/test/mjsunit/debug-liveedit-compile-error.js index 99ac0314a..2fd6aedab 100644 --- a/deps/v8/test/mjsunit/debug-liveedit-compile-error.js +++ b/deps/v8/test/mjsunit/debug-liveedit-compile-error.js @@ -56,3 +56,5 @@ assertEquals("Unexpected token )", caught_exception.details.syntaxErrorMessage); assertEquals(2, caught_exception.details.position.start.line); + + diff --git a/deps/v8/test/mjsunit/elements-kind.js b/deps/v8/test/mjsunit/elements-kind.js index d95255605..0e8e209ef 100644 --- a/deps/v8/test/mjsunit/elements-kind.js +++ b/deps/v8/test/mjsunit/elements-kind.js @@ -28,9 +28,10 @@ // Flags: --allow-natives-syntax --smi-only-arrays --expose-gc // Flags: --notrack_allocation_sites -// Limit the number of stress runs to reduce polymorphism it defeats some of -// they assumptions made about how elements transitions work because transition -// stubs end up going generic. Flags: --stress-runs=2 +// Limit the number of stress runs to reduce polymorphism it defeats some of the +// assumptions made about how elements transitions work because transition stubs +// end up going generic. +// Flags: --stress-runs=2 // Test element kind of objects. // Since --smi-only-arrays affects builtins, its default setting at compile diff --git a/deps/v8/test/mjsunit/error-accessors.js b/deps/v8/test/mjsunit/error-accessors.js index cdaf080a3..958105024 100644 --- a/deps/v8/test/mjsunit/error-accessors.js +++ b/deps/v8/test/mjsunit/error-accessors.js @@ -51,3 +51,4 @@ assertEquals("x is not defined", o.message = "another message"; assertEquals("another message", o.message); assertEquals("x is not defined", error2.message); + diff --git a/deps/v8/test/mjsunit/harmony/generators-parsing.js b/deps/v8/test/mjsunit/harmony/generators-parsing.js new file mode 100644 index 000000000..0e5494df1 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/generators-parsing.js @@ -0,0 +1,100 @@ +// 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. + +// Flags: --harmony-generators + +// Test basic generator syntax. + +// Yield statements. +function* g() { yield 3; yield 4; } + +// Yield expressions. +function* g() { (yield 3) + (yield 4); } + +// You can have a generator in strict mode. +function* g() { "use strict"; yield 3; yield 4; } + +// Generator expression. +(function* () { yield 3; }); + +// Named generator expression. +(function* g() { yield 3; }); + +// A generator without a yield is specified as causing an early error. This +// behavior is currently unimplemented. See +// https://bugs.ecmascript.org/show_bug.cgi?id=1283. +function* g() { } + +// A YieldExpression in the RHS of a YieldExpression is currently specified as +// causing an early error. This behavior is currently unimplemented. See +// https://bugs.ecmascript.org/show_bug.cgi?id=1283. +function* g() { yield yield 1; } +function* g() { yield 3 + (yield 4); } + +// Generator definitions with a name of "yield" are not specifically ruled out +// by the spec, as the `yield' name is outside the generator itself. However, +// in strict-mode, "yield" is an invalid identifier. +function* yield() { (yield 3) + (yield 4); } +assertThrows("function* yield() { \"use strict\"; (yield 3) + (yield 4); }", + SyntaxError); + +// In classic mode, yield is a normal identifier, outside of generators. +function yield(yield) { yield: yield (yield + yield (0)); } + +// Yield is always valid as a key in an object literal. +({ yield: 1 }); +function* g() { yield ({ yield: 1 }) } +function* g() { yield ({ get yield() { return 1; }}) } + +// Checks that yield is a valid label in classic mode, but not valid in a strict +// mode or in generators. +function f() { yield: 1 } +assertThrows("function f() { \"use strict\"; yield: 1 }", SyntaxError) +assertThrows("function f*() { yield: 1 }", SyntaxError) + +// Yield is only a keyword in the body of the generator, not in nested +// functions. +function* g() { function f() { yield (yield + yield (0)); } } + +// Yield needs a RHS. +assertThrows("function* g() { yield; }", SyntaxError); + +// Yield in a generator is not an identifier. +assertThrows("function* g() { yield = 10; }", SyntaxError); + +// Yield binds very loosely, so this parses as "yield (3 + yield 4)", which is +// invalid. +assertThrows("function* g() { yield 3 + yield 4; }", SyntaxError); + +// Yield is still a future-reserved-word in strict mode +assertThrows("function f() { \"use strict\"; var yield = 13; }", SyntaxError); + +// The name of the NFE is let-bound in G, so is invalid. +assertThrows("function* g() { yield (function yield() {}); }", SyntaxError); + +// In generators, yield is invalid as a formal argument name. +assertThrows("function* g(yield) { yield (10); }", SyntaxError); diff --git a/deps/v8/test/mjsunit/harmony/object-observe.js b/deps/v8/test/mjsunit/harmony/object-observe.js index 584d9e82d..263154a40 100644 --- a/deps/v8/test/mjsunit/harmony/object-observe.js +++ b/deps/v8/test/mjsunit/harmony/object-observe.js @@ -26,7 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Flags: --harmony-observation --harmony-proxies --harmony-collections -// Flags: --allow-natives-syntax +// Flags: --harmony-symbols --allow-natives-syntax var allObservers = []; function reset() { @@ -448,6 +448,29 @@ observer.assertCallbackRecords([ ]); +// Observing symbol properties (not). +print("*****") +reset(); +var obj = {} +var symbol = Symbol("secret"); +Object.observe(obj, observer.callback); +obj[symbol] = 3; +delete obj[symbol]; +Object.defineProperty(obj, symbol, {get: function() {}, configurable: true}); +Object.defineProperty(obj, symbol, {value: 6}); +Object.defineProperty(obj, symbol, {writable: false}); +delete obj[symbol]; +Object.defineProperty(obj, symbol, {value: 7}); +++obj[symbol]; +obj[symbol]++; +obj[symbol] *= 3; +delete obj[symbol]; +obj.__defineSetter__(symbol, function() {}); +obj.__defineGetter__(symbol, function() {}); +Object.deliverChangeRecords(observer.callback); +observer.assertNotCalled(); + + // Test all kinds of objects generically. function TestObserveConfigurable(obj, prop) { reset(); diff --git a/deps/v8/test/mjsunit/harmony/proxies-symbols.js b/deps/v8/test/mjsunit/harmony/proxies-symbols.js new file mode 100644 index 000000000..8920e3996 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/proxies-symbols.js @@ -0,0 +1,106 @@ +// 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. + +// Flags: --harmony-proxies --harmony-symbols + + +// Helper. + +function TestWithProxies(test, x, y, z) { + test(Proxy.create, x, y, z) + test(function(h) {return Proxy.createFunction(h, function() {})}, x, y, z) +} + + +// No symbols should leak to proxy traps. + +function TestNoSymbolsToTrap(handler) { + TestWithProxies(TestNoSymbolsToTrap2, handler) +} + +function TestNoSymbolsToTrap2(create, handler) { + var p = create(handler) + var o = Object.create(p) + var symbol = Symbol("secret") + + assertFalse(symbol in p) + assertFalse(symbol in o) + assertEquals(undefined, p[symbol]) + assertEquals(undefined, o[symbol]) + assertEquals(47, p[symbol] = 47) + assertEquals(47, o[symbol] = 47) + assertFalse(delete p[symbol]) + assertTrue(delete o[symbol]) + assertTrue(delete o[symbol]) + assertFalse({}.hasOwnProperty.call(p, symbol)) + assertFalse({}.hasOwnProperty.call(o, symbol)) + assertEquals(undefined, Object.getOwnPropertyDescriptor(p, symbol)) + assertEquals(undefined, Object.getOwnPropertyDescriptor(o, symbol)) +} + + +TestNoSymbolsToTrap({ + has: assertUnreachable, + hasOwn: assertUnreachable, + get: assertUnreachable, + set: assertUnreachable, + delete: assertUnreachable, + getPropertyDescriptor: assertUnreachable, + getOwnPropertyDescriptor: assertUnreachable, + defineProperty: assertUnreachable +}) + + +// All symbols returned from proxy traps should be filtered. + +function TestNoSymbolsFromTrap(handler) { + TestWithProxies(TestNoSymbolsFromTrap2, handler) +} + +function TestNoSymbolsFromTrap2(create, handler) { + var p = create(handler) + var o = Object.create(p) + + assertEquals(0, Object.keys(p).length) + assertEquals(0, Object.keys(o).length) + assertEquals(0, Object.getOwnPropertyNames(p).length) + assertEquals(0, Object.getOwnPropertyNames(o).length) + for (var n in p) assertUnreachable() + for (var n in o) assertUnreachable() +} + + +function MakeSymbolArray() { + return [Symbol(), Symbol("a")] +} + +TestNoSymbolsFromTrap({ + enumerate: MakeSymbolArray, + keys: MakeSymbolArray, + getPropertyNames: MakeSymbolArray, + getOwnPropertyNames: MakeSymbolArray +}) diff --git a/deps/v8/test/mjsunit/harmony/symbols.js b/deps/v8/test/mjsunit/harmony/symbols.js index cdc63628a..a3f6e5720 100644 --- a/deps/v8/test/mjsunit/harmony/symbols.js +++ b/deps/v8/test/mjsunit/harmony/symbols.js @@ -34,20 +34,22 @@ var symbols = [] function TestNew() { function IndirectSymbol() { return new Symbol } function indirect() { return new IndirectSymbol() } - for (var i = 0; i < 10; ++i) { - symbols.push(new Symbol) - symbols.push(new Symbol()) - symbols.push(Symbol()) - symbols.push(indirect()) - } - %OptimizeFunctionOnNextCall(indirect) - indirect() // Call once before GC throws away type feedback. - gc() // Promote existing symbols and then allocate some more. - for (var i = 0; i < 10; ++i) { - symbols.push(new Symbol) - symbols.push(new Symbol()) - symbols.push(Symbol()) - symbols.push(indirect()) + for (var i = 0; i < 2; ++i) { + for (var j = 0; j < 5; ++j) { + symbols.push(Symbol()) + symbols.push(Symbol(undefined)) + symbols.push(Symbol("66")) + symbols.push(Symbol(66)) + symbols.push(Symbol(Symbol())) + symbols.push((new Symbol).valueOf()) + symbols.push((new Symbol()).valueOf()) + symbols.push((new Symbol(Symbol())).valueOf()) + symbols.push(Object(Symbol()).valueOf()) + symbols.push((indirect()).valueOf()) + } + %OptimizeFunctionOnNextCall(indirect) + indirect() // Call once before GC throws away type feedback. + gc() // Promote existing symbols and then allocate some more. } } TestNew() @@ -55,23 +57,91 @@ TestNew() function TestType() { for (var i in symbols) { - assertTrue(%_IsSymbol(symbols[i])) - assertEquals("object", typeof symbols[i]) - assertTrue(typeof symbols[i] === "object") - assertEquals("[object Symbol]", Object.prototype.toString.call(symbols[i])) + assertEquals("symbol", typeof symbols[i]) + assertTrue(typeof symbols[i] === "symbol") + assertEquals(null, %_ClassOf(symbols[i])) + assertEquals("Symbol", %_ClassOf(new Symbol(symbols[i]))) + assertEquals("Symbol", %_ClassOf(Object(symbols[i]))) } } TestType() +function TestPrototype() { + assertSame(Object.prototype, Symbol.prototype.__proto__) + assertSame(Symbol.prototype, Symbol().__proto__) + assertSame(Symbol.prototype, Symbol(Symbol()).__proto__) + assertSame(Symbol.prototype, (new Symbol).__proto__) + assertSame(Symbol.prototype, (new Symbol()).__proto__) + assertSame(Symbol.prototype, (new Symbol(Symbol())).__proto__) + assertSame(Symbol.prototype, Object(Symbol()).__proto__) + for (var i in symbols) { + assertSame(Symbol.prototype, symbols[i].__proto__) + } +} +TestPrototype() + + +function TestName() { + for (var i in symbols) { + var name = symbols[i].name + assertTrue(name === undefined || name === "66") + } +} +TestName() + + +function TestToString() { + for (var i in symbols) { + assertThrows(function() { String(symbols[i]) }, TypeError) + assertThrows(function() { symbols[i] + "" }, TypeError) + assertThrows(function() { symbols[i].toString() }, TypeError) + assertThrows(function() { (new Symbol(symbols[i])).toString() }, TypeError) + assertThrows(function() { Object(symbols[i]).toString() }, TypeError) + assertEquals("[object Symbol]", Object.prototype.toString.call(symbols[i])) + } +} +TestToString() + + +function TestToBoolean() { + for (var i in symbols) { + assertTrue(Boolean(symbols[i]).valueOf()) + assertFalse(!symbols[i]) + assertTrue(!!symbols[i]) + assertTrue(symbols[i] && true) + assertFalse(!symbols[i] && false) + assertTrue(!symbols[i] || true) + assertEquals(1, symbols[i] ? 1 : 2) + assertEquals(2, !symbols[i] ? 1 : 2) + if (!symbols[i]) assertUnreachable(); + if (symbols[i]) {} else assertUnreachable(); + } +} +TestToBoolean() + + +function TestToNumber() { + for (var i in symbols) { + assertSame(NaN, Number(symbols[i]).valueOf()) + assertSame(NaN, symbols[i] + 0) + } +} +TestToNumber() + + function TestEquality() { - // Every symbol should equal itself. + // Every symbol should equal itself, and non-strictly equal its wrapper. for (var i in symbols) { assertSame(symbols[i], symbols[i]) assertEquals(symbols[i], symbols[i]) assertTrue(Object.is(symbols[i], symbols[i])) assertTrue(symbols[i] === symbols[i]) assertTrue(symbols[i] == symbols[i]) + assertFalse(symbols[i] === new Symbol(symbols[i])) + assertFalse(new Symbol(symbols[i]) === symbols[i]) + assertTrue(symbols[i] == new Symbol(symbols[i])) + assertTrue(new Symbol(symbols[i]) == symbols[i]) } // All symbols should be distinct. @@ -82,14 +152,25 @@ function TestEquality() { assertFalse(symbols[i] == symbols[j]) } } + + // Symbols should not be equal to any other value (and the test terminates). + var values = [347, 1.275, NaN, "string", null, undefined, {}, function() {}] + for (var i in symbols) { + for (var j in values) { + assertFalse(symbols[i] === values[j]) + assertFalse(values[j] === symbols[i]) + assertFalse(symbols[i] == values[j]) + assertFalse(values[j] == symbols[i]) + } + } } TestEquality() function TestGet() { for (var i in symbols) { - assertEquals("[object Symbol]", symbols[i].toString()) - assertEquals(undefined, symbols[i].valueOf) + assertThrows(function() { symbols[i].toString() }, TypeError) + assertEquals(symbols[i], symbols[i].valueOf()) assertEquals(undefined, symbols[i].a) assertEquals(undefined, symbols[i]["a" + "b"]) assertEquals(undefined, symbols[i]["" + "1"]) @@ -102,7 +183,9 @@ TestGet() function TestSet() { for (var i in symbols) { symbols[i].toString = 0 - assertEquals("[object Symbol]", symbols[i].toString()) + assertThrows(function() { symbols[i].toString() }, TypeError) + symbols[i].valueOf = 0 + assertEquals(symbols[i], symbols[i].valueOf()) symbols[i].a = 0 assertEquals(undefined, symbols[i].a) symbols[i]["a" + "b"] = 0 @@ -145,9 +228,12 @@ TestCollections() function TestKeySet(obj) { + assertTrue(%HasFastProperties(obj)) // Set the even symbols via assignment. for (var i = 0; i < symbols.length; i += 2) { obj[symbols[i]] = i + // Object should remain in fast mode until too many properties were added. + assertTrue(%HasFastProperties(obj) || i >= 30) } } @@ -179,7 +265,7 @@ function TestKeyHas() { function TestKeyEnum(obj) { for (var name in obj) { - assertFalse(%_IsSymbol(name)) + assertEquals("string", typeof name) } } @@ -188,21 +274,9 @@ function TestKeyNames(obj) { assertEquals(0, Object.keys(obj).length) var names = Object.getOwnPropertyNames(obj) - assertTrue(symbols.length <= names.length) - // TODO(rossberg): once we have iterators, the following would be: - // var expected = new Set(symbols) - var expected = new Set - for (var i = 0; i < symbols.length; ++i) expected.add(symbols[i]) - for (var i = 0; i < names.length; ++i) { - var name = names[i] - var asString = String(name) - if (asString !== name) { - assertEquals("[object Symbol]", asString) - assertTrue(expected.has(name)) - expected.delete(name) - } + for (var i in names) { + assertEquals("string", typeof names[i]) } - assertEquals(0, expected.size) } @@ -242,3 +316,19 @@ for (var i in objs) { TestKeyDescriptor(obj) TestKeyDelete(obj) } + + +function TestCachedKeyAfterScavenge() { + gc(); + // Keyed property lookup are cached. Hereby we assume that the keys are + // tenured, so that we only have to clear the cache between mark compacts, + // but not between scavenges. This must also apply for symbol keys. + var key = Symbol("key"); + var a = {}; + a[key] = "abc"; + + for (var i = 0; i < 1000000; i++) { + a[key] += "a"; // Allocations cause a scavenge. + } +} +TestCachedKeyAfterScavenge(); diff --git a/deps/v8/test/mjsunit/harmony/typedarrays.js b/deps/v8/test/mjsunit/harmony/typedarrays.js new file mode 100644 index 000000000..9b01ba60e --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/typedarrays.js @@ -0,0 +1,136 @@ +// 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. + +// Flags: --harmony-typed-arrays + +function TestByteLength(param, expectedByteLength) { + var ab = new __ArrayBuffer(param); + assertSame(expectedByteLength, ab.byteLength); +} + +function TestArrayBufferCreation() { + TestByteLength(1, 1); + TestByteLength(256, 256); + TestByteLength(-10, 0); + TestByteLength(2.567, 2); + TestByteLength(-2.567, 0); + + TestByteLength("abc", 0); + + TestByteLength(0, 0); + + assertThrows(function() { + var ab1 = new __ArrayBuffer(0xFFFFFFFFFFFF) + }, RangeError); + + var ab = new __ArrayBuffer(); + assertSame(0, ab.byteLength); +} + +TestArrayBufferCreation(); + +function TestByteLengthNotWritable() { + var ab = new __ArrayBuffer(1024); + assertSame(1024, ab.byteLength); + + assertThrows(function() { "use strict"; ab.byteLength = 42; }, TypeError); +} + +TestByteLengthNotWritable(); + +function TestSlice(expectedResultLen, initialLen, start, end) { + var ab = new __ArrayBuffer(initialLen); + var slice = ab.slice(start, end); + assertSame(expectedResultLen, slice.byteLength); +} + +function TestArrayBufferSlice() { + var ab = new __ArrayBuffer(1024); + var ab1 = ab.slice(512, 1024); + assertSame(512, ab1.byteLength); + + TestSlice(512, 1024, 512, 1024); + TestSlice(512, 1024, 512); + + TestSlice(0, 0, 1, 20); + TestSlice(100, 100, 0, 100); + TestSlice(100, 100, 0, 1000); + TestSlice(0, 100, 5, 1); + + TestSlice(1, 100, -11, -10); + TestSlice(9, 100, -10, 99); + TestSlice(0, 100, -10, 80); + TestSlice(10, 100, 80, -10); + + TestSlice(10, 100, 90, "100"); + TestSlice(10, 100, "90", "100"); + + TestSlice(0, 100, 90, "abc"); + TestSlice(10, 100, "abc", 10); + + TestSlice(10, 100, 0.96, 10.96); + TestSlice(10, 100, 0.96, 10.01); + TestSlice(10, 100, 0.01, 10.01); + TestSlice(10, 100, 0.01, 10.96); + + + TestSlice(10, 100, 90); + TestSlice(10, 100, -10); +} + +TestArrayBufferSlice(); + +// Test property attribute [[Enumerable]] +function TestEnumerable(func) { + function props(x) { + var array = []; + for (var p in x) array.push(p); + return array.sort(); + } + assertArrayEquals([], props(func)); + assertArrayEquals([], props(func.prototype)); + assertArrayEquals([], props(new func())); +} +TestEnumerable(__ArrayBuffer); + + +// Test arbitrary properties on ArrayBuffer +function TestArbitrary(m) { + function TestProperty(map, property, value) { + map[property] = value; + assertEquals(value, map[property]); + } + for (var i = 0; i < 20; i++) { + TestProperty(m, i, 'val' + i); + TestProperty(m, 'foo' + i, 'bar' + i); + } +} +TestArbitrary(new __ArrayBuffer(256)); + + +// Test direct constructor call +assertTrue(__ArrayBuffer() instanceof __ArrayBuffer); diff --git a/deps/v8/test/mjsunit/json.js b/deps/v8/test/mjsunit/json.js index 79826dbef..c72c15368 100644 --- a/deps/v8/test/mjsunit/json.js +++ b/deps/v8/test/mjsunit/json.js @@ -225,23 +225,28 @@ TestInvalid('"Garbage""After string"'); // Stringify -assertEquals("true", JSON.stringify(true)); -assertEquals("false", JSON.stringify(false)); -assertEquals("null", JSON.stringify(null)); -assertEquals("false", JSON.stringify({toJSON: function () { return false; }})); -assertEquals("4", JSON.stringify(4)); -assertEquals('"foo"', JSON.stringify("foo")); -assertEquals("null", JSON.stringify(Infinity)); -assertEquals("null", JSON.stringify(-Infinity)); -assertEquals("null", JSON.stringify(NaN)); -assertEquals("4", JSON.stringify(new Number(4))); -assertEquals('"bar"', JSON.stringify(new String("bar"))); - -assertEquals('"foo\\u0000bar"', JSON.stringify("foo\0bar")); -assertEquals('"f\\"o\'o\\\\b\\ba\\fr\\nb\\ra\\tz"', - JSON.stringify("f\"o\'o\\b\ba\fr\nb\ra\tz")); - -assertEquals("[1,2,3]", JSON.stringify([1, 2, 3])); +function TestStringify(expected, input) { + assertEquals(expected, JSON.stringify(input)); + assertEquals(expected, JSON.stringify(input, null, 0)); +} + +TestStringify("true", true); +TestStringify("false", false); +TestStringify("null", null); +TestStringify("false", {toJSON: function () { return false; }}); +TestStringify("4", 4); +TestStringify('"foo"', "foo"); +TestStringify("null", Infinity); +TestStringify("null", -Infinity); +TestStringify("null", NaN); +TestStringify("4", new Number(4)); +TestStringify('"bar"', new String("bar")); + +TestStringify('"foo\\u0000bar"', "foo\0bar"); +TestStringify('"f\\"o\'o\\\\b\\ba\\fr\\nb\\ra\\tz"', + "f\"o\'o\\b\ba\fr\nb\ra\tz"); + +TestStringify("[1,2,3]", [1, 2, 3]); assertEquals("[\n 1,\n 2,\n 3\n]", JSON.stringify([1, 2, 3], null, 1)); assertEquals("[\n 1,\n 2,\n 3\n]", JSON.stringify([1, 2, 3], null, 2)); assertEquals("[\n 1,\n 2,\n 3\n]", @@ -256,33 +261,38 @@ assertEquals("[1,2,[3,[4],5],6,7]", JSON.stringify([1, 2, [3, [4], 5], 6, 7], null)); assertEquals("[2,4,[6,[8],10],12,14]", JSON.stringify([1, 2, [3, [4], 5], 6, 7], DoubleNumbers)); -assertEquals('["a","ab","abc"]', JSON.stringify(["a","ab","abc"])); -assertEquals('{"a":1,"c":true}', - JSON.stringify({ a : 1, - b : function() { 1 }, - c : true, - d : function() { 2 } })); -assertEquals('[1,null,true,null]', - JSON.stringify([1, function() { 1 }, true, function() { 2 }])); -assertEquals('"toJSON 123"', - JSON.stringify({ toJSON : function() { return 'toJSON 123'; } })); -assertEquals('{"a":321}', - JSON.stringify({ a : { toJSON : function() { return 321; } } })); +TestStringify('["a","ab","abc"]', ["a","ab","abc"]); +TestStringify('{"a":1,"c":true}', { a : 1, + b : function() { 1 }, + c : true, + d : function() { 2 } }); +TestStringify('[1,null,true,null]', + [1, function() { 1 }, true, function() { 2 }]); +TestStringify('"toJSON 123"', + { toJSON : function() { return 'toJSON 123'; } }); +TestStringify('{"a":321}', + { a : { toJSON : function() { return 321; } } }); var counter = 0; assertEquals('{"getter":123}', JSON.stringify({ get getter() { counter++; return 123; } })); assertEquals(1, counter); -assertEquals('{"a":"abc","b":"\u1234bc"}', - JSON.stringify({ a : "abc", b : "\u1234bc" })); +assertEquals('{"getter":123}', + JSON.stringify({ get getter() { counter++; return 123; } }, + null, + 0)); +assertEquals(2, counter); + +TestStringify('{"a":"abc","b":"\u1234bc"}', + { a : "abc", b : "\u1234bc" }); var a = { a : 1, b : 2 }; delete a.a; -assertEquals('{"b":2}', JSON.stringify(a)); +TestStringify('{"b":2}', a); var b = {}; b.__proto__ = { toJSON : function() { return 321;} }; -assertEquals("321", JSON.stringify(b)); +TestStringify("321", b); var array = [""]; var expected = '""'; @@ -291,18 +301,19 @@ for (var i = 0; i < 10000; i++) { expected = '"",' + expected; } expected = '[' + expected + ']'; -assertEquals(expected, JSON.stringify(array)); +TestStringify(expected, array); var circular = [1, 2, 3]; circular[2] = circular; assertThrows(function () { JSON.stringify(circular); }, TypeError); +assertThrows(function () { JSON.stringify(circular, null, 0); }, TypeError); var singleton = []; var multiOccurrence = [singleton, singleton, singleton]; -assertEquals("[[],[],[]]", JSON.stringify(multiOccurrence)); +TestStringify("[[],[],[]]", multiOccurrence); -assertEquals('{"x":5,"y":6}', JSON.stringify({x:5,y:6})); +TestStringify('{"x":5,"y":6}', {x:5,y:6}); assertEquals('{"x":5}', JSON.stringify({x:5,y:6}, ['x'])); assertEquals('{\n "a": "b",\n "c": "d"\n}', JSON.stringify({a:"b",c:"d"}, null, 1)); @@ -312,7 +323,7 @@ assertEquals('{"y":6,"x":5}', JSON.stringify({x:5,y:6}, ['y', 'x'])); var checker = {}; var array = [checker]; checker.toJSON = function(key) { return 1 + key; }; -assertEquals('["10"]', JSON.stringify(array)); +TestStringify('["10"]', array); // The gap is capped at ten characters if specified as string. assertEquals('{\n "a": "b",\n "c": "d"\n}', @@ -329,12 +340,11 @@ assertEquals('{"x":"42"}', JSON.stringify({x: String}, newx)); assertEquals('{"x":42}', JSON.stringify({x: Number}, newx)); assertEquals('{"x":true}', JSON.stringify({x: Boolean}, newx)); -assertEquals(undefined, JSON.stringify(undefined)); -assertEquals(undefined, JSON.stringify(function () { })); +TestStringify(undefined, undefined); +TestStringify(undefined, function () { }); // Arrays with missing, undefined or function elements have those elements // replaced by null. -assertEquals("[null,null,null]", - JSON.stringify([undefined,,function(){}])); +TestStringify("[null,null,null]", [undefined,,function(){}]); // Objects with undefined or function properties (including replaced properties) // have those properties ignored. @@ -415,16 +425,15 @@ var re = /Is callable/; var reJSON = /Is callable/; reJSON.toJSON = function() { return "has toJSON"; }; -assertEquals( - '[37,null,1,"foo","37","true",null,"has toJSON",{},"has toJSON"]', - JSON.stringify([num37, numFoo, numTrue, - strFoo, str37, strTrue, - func, funcJSON, re, reJSON])); +TestStringify('[37,null,1,"foo","37","true",null,"has toJSON",{},"has toJSON"]', + [num37, numFoo, numTrue, + strFoo, str37, strTrue, + func, funcJSON, re, reJSON]); var oddball = Object(42); oddball.__proto__ = { __proto__: null, toString: function() { return true; } }; -assertEquals('1', JSON.stringify(oddball)); +TestStringify('1', oddball); var getCount = 0; var callCount = 0; @@ -433,10 +442,10 @@ var counter = { get toJSON() { getCount++; return 42; }; } }; // RegExps are not callable, so they are stringified as objects. -assertEquals('{}', JSON.stringify(/regexp/)); -assertEquals('42', JSON.stringify(counter)); -assertEquals(1, getCount); -assertEquals(1, callCount); +TestStringify('{}', /regexp/); +TestStringify('42', counter); +assertEquals(2, getCount); +assertEquals(2, callCount); var oddball2 = Object(42); var oddball3 = Object("foo"); @@ -445,13 +454,13 @@ oddball3.__proto__ = { __proto__: null, valueOf: function() { return true; } }; oddball2.__proto__ = { __proto__: null, toJSON: function () { return oddball3; } } -assertEquals('"true"', JSON.stringify(oddball2)); +TestStringify('"true"', oddball2); var falseNum = Object("37"); falseNum.__proto__ = Number.prototype; falseNum.toString = function() { return 42; }; -assertEquals('"42"', JSON.stringify(falseNum)); +TestStringify('"42"', falseNum); // Parse an object value as __proto__. var o1 = JSON.parse('{"__proto__":[]}'); @@ -472,4 +481,4 @@ assertTrue(o2.hasOwnProperty("__proto__")); assertTrue(Object.prototype.isPrototypeOf(o2)); var json = '{"stuff before slash\\\\stuff after slash":"whatever"}'; -assertEquals(json, JSON.stringify(JSON.parse(json))); +TestStringify(json, JSON.parse(json)); diff --git a/deps/v8/test/mjsunit/json2.js b/deps/v8/test/mjsunit/json2.js index 4c0b8f58c..cf20b909b 100644 --- a/deps/v8/test/mjsunit/json2.js +++ b/deps/v8/test/mjsunit/json2.js @@ -25,13 +25,19 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --allow-natives-syntax +// Flags: --allow-natives-syntax --expose-externalize-string // Test JSON.stringify on the global object. var a = 12345; assertTrue(JSON.stringify(this).indexOf('"a":12345') > 0); +assertTrue(JSON.stringify(this, null, 0).indexOf('"a":12345') > 0); // Test JSON.stringify of array in dictionary mode. +function TestStringify(expected, input) { + assertEquals(expected, JSON.stringify(input)); + assertEquals(expected, JSON.stringify(input, null, 0)); +} + var array_1 = []; var array_2 = []; array_1[100000] = 1; @@ -42,25 +48,25 @@ for (var i = 0; i < 100000; i++) { } expected_1 = '[' + nulls + '1]'; expected_2 = '[' + nulls + 'null]'; -assertEquals(expected_1, JSON.stringify(array_1)); -assertEquals(expected_2, JSON.stringify(array_2)); +TestStringify(expected_1, array_1); +TestStringify(expected_2, array_2); // Test JSValue with custom prototype. var num_wrapper = Object(42); num_wrapper.__proto__ = { __proto__: null, toString: function() { return true; } }; -assertEquals('1', JSON.stringify(num_wrapper)); +TestStringify('1', num_wrapper); var str_wrapper = Object('2'); str_wrapper.__proto__ = { __proto__: null, toString: function() { return true; } }; -assertEquals('"true"', JSON.stringify(str_wrapper)); +TestStringify('"true"', str_wrapper); var bool_wrapper = Object(false); bool_wrapper.__proto__ = { __proto__: null, toString: function() { return true; } }; // Note that toString function is not evaluated here! -assertEquals('false', JSON.stringify(bool_wrapper)); +TestStringify('false', bool_wrapper); // Test getters. var counter = 0; @@ -68,8 +74,8 @@ var getter_obj = { get getter() { counter++; return 123; } }; -assertEquals('{"getter":123}', JSON.stringify(getter_obj)); -assertEquals(1, counter); +TestStringify('{"getter":123}', getter_obj); +assertEquals(2, counter); // Test toJSON function. var tojson_obj = { toJSON: function() { @@ -77,8 +83,8 @@ var tojson_obj = { toJSON: function() { return [1, 2]; }, a: 1}; -assertEquals('[1,2]', JSON.stringify(tojson_obj)); -assertEquals(2, counter); +TestStringify('[1,2]', tojson_obj); +assertEquals(4, counter); // Test that we don't recursively look for the toJSON function. var tojson_proto_obj = { a: 'fail' }; @@ -86,7 +92,7 @@ tojson_proto_obj.__proto__ = { toJSON: function() { counter++; return tojson_obj; } }; -assertEquals('{"a":1}', JSON.stringify(tojson_proto_obj)); +TestStringify('{"a":1}', tojson_proto_obj); // Test toJSON produced by a getter. var tojson_via_getter = { get toJSON() { @@ -96,43 +102,44 @@ var tojson_via_getter = { get toJSON() { }; }, a: 1 }; -assertEquals('321', JSON.stringify(tojson_via_getter)); +TestStringify('321', tojson_via_getter); // Test toJSON with key. tojson_obj = { toJSON: function(key) { return key + key; } }; var tojson_with_key_1 = { a: tojson_obj, b: tojson_obj }; -assertEquals('{"a":"aa","b":"bb"}', JSON.stringify(tojson_with_key_1)); +TestStringify('{"a":"aa","b":"bb"}', tojson_with_key_1); var tojson_with_key_2 = [ tojson_obj, tojson_obj ]; -assertEquals('["00","11"]', JSON.stringify(tojson_with_key_2)); +TestStringify('["00","11"]', tojson_with_key_2); // Test toJSON with exception. var tojson_ex = { toJSON: function(key) { throw "123" } }; assertThrows(function() { JSON.stringify(tojson_ex); }); +assertThrows(function() { JSON.stringify(tojson_ex, null, 0); }); // Test toJSON with access to this. var obj = { toJSON: function(key) { return this.a + key; }, a: "x" }; -assertEquals('{"y":"xy"}', JSON.stringify({y: obj})); +TestStringify('{"y":"xy"}', {y: obj}); // Test holes in arrays. var fast_smi = [1, 2, 3, 4]; fast_smi.__proto__ = [7, 7, 7, 7]; delete fast_smi[2]; assertTrue(%HasFastSmiElements(fast_smi)); -assertEquals("[1,2,7,4]", JSON.stringify(fast_smi)); +TestStringify("[1,2,7,4]", fast_smi); var fast_double = [1.1, 2, 3, 4]; fast_double.__proto__ = [7, 7, 7, 7]; delete fast_double[2]; assertTrue(%HasFastDoubleElements(fast_double)); -assertEquals("[1.1,2,7,4]", JSON.stringify(fast_double)); +TestStringify("[1.1,2,7,4]", fast_double); var fast_obj = [1, 2, {}, {}]; fast_obj.__proto__ = [7, 7, 7, 7]; delete fast_obj[2]; assertTrue(%HasFastObjectElements(fast_obj)); -assertEquals("[1,2,7,{}]", JSON.stringify(fast_obj)); +TestStringify("[1,2,7,{}]", fast_obj); var getter_side_effect = { a: 1, get b() { @@ -146,8 +153,28 @@ var getter_side_effect = { a: 1, assertEquals('{"a":1,"b":2,"d":4}', JSON.stringify(getter_side_effect)); assertEquals('{"b":2,"d":4,"e":5}', JSON.stringify(getter_side_effect)); +getter_side_effect = { a: 1, + get b() { + delete this.a; + delete this.c; + this.e = 5; + return 2; + }, + c: 3, + d: 4 }; +assertEquals('{"a":1,"b":2,"d":4}', + JSON.stringify(getter_side_effect, null, 0)); +assertEquals('{"b":2,"d":4,"e":5}', + JSON.stringify(getter_side_effect, null, 0)); + var non_enum = {}; non_enum.a = 1; Object.defineProperty(non_enum, "b", { value: 2, enumerable: false }); non_enum.c = 3; -assertEquals('{"a":1,"c":3}', JSON.stringify(non_enum)); +TestStringify('{"a":1,"c":3}', non_enum); + +var str = "external"; +try { + externalizeString(str, true); +} catch (e) { } +TestStringify("\"external\"", str, null, 0); diff --git a/deps/v8/test/mjsunit/nans.js b/deps/v8/test/mjsunit/nans.js new file mode 100644 index 000000000..d212afdee --- /dev/null +++ b/deps/v8/test/mjsunit/nans.js @@ -0,0 +1,103 @@ +// 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. + +// Flags: --allow-natives-syntax + + +// Test that both kinds of NaNs (signaling or quiet) do not signal + +function TestAllModes(f) { + f(); // Runtime + f(); // IC + f(); // IC second time + %OptimizeFunctionOnNextCall(f); + f(); // hydrogen +} + +function TestDoubleSignalingNan() { + // NaN with signal bit set + function f() { + var bytes = new Uint32Array([1, 0x7FF00000]); + var doubles = new Float64Array(bytes.buffer); + assertTrue(isNaN(doubles[0])); + assertTrue(isNaN(doubles[0]*2.0)); + assertTrue(isNaN(doubles[0] + 0.5)); + } + + TestAllModes(f); +} + +TestDoubleSignalingNan(); + +function TestDoubleQuietNan() { + // NaN with signal bit cleared + function f() { + var bytes = new Uint32Array([0, 0x7FF80000]); + var doubles = new Float64Array(bytes.buffer); + assertTrue(isNaN(doubles[0])); + assertTrue(isNaN(doubles[0]*2.0)); + assertTrue(isNaN(doubles[0] + 0.5)); + } + + TestAllModes(f); +} + +TestDoubleQuietNan(); + +function TestFloatSignalingNan() { + // NaN with signal bit set + function f() { + var bytes = new Uint32Array([0x7F800001]); + var floats = new Float32Array(bytes.buffer); + assertTrue(isNaN(floats[0])); + assertTrue(isNaN(floats[0]*2.0)); + assertTrue(isNaN(floats[0] + 0.5)); + } + + TestAllModes(f); +} + +TestFloatSignalingNan(); + +function TestFloatQuietNan() { + // NaN with signal bit cleared + function f() { + var bytes = new Uint32Array([0x7FC00000]); + var floats = new Float32Array(bytes.buffer); + assertTrue(isNaN(floats[0])); + assertTrue(isNaN(floats[0]*2.0)); + assertTrue(isNaN(floats[0] + 0.5)); + } + + TestAllModes(f); +} + +TestFloatQuietNan(); + + + + diff --git a/deps/v8/test/mjsunit/regress/external-and-normal-array-polymorphism.js b/deps/v8/test/mjsunit/regress/external-and-normal-array-polymorphism.js new file mode 100644 index 000000000..0ac1545ca --- /dev/null +++ b/deps/v8/test/mjsunit/regress/external-and-normal-array-polymorphism.js @@ -0,0 +1,48 @@ +// 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. + +function store_generator(compare) { + return function(a,i,v) { + a[i] = v; + assertEquals(compare, a[i]); + assertEquals(compare, a[i]); + } +} + +f = store_generator(5); +a = [0,0,0]; +f(a,0,5); +a = [0,0,0]; +f(a,1,5); +a = [0,0,0]; +f(a,2,5); + +f = store_generator(5.5); +a = new Float32Array(5); +f(a,0,5.5); +f(a,1,5.5); +f(a,2,5.5); diff --git a/deps/v8/test/mjsunit/regress/negative_lookup.js b/deps/v8/test/mjsunit/regress/negative_lookup.js new file mode 100644 index 000000000..e23e365fc --- /dev/null +++ b/deps/v8/test/mjsunit/regress/negative_lookup.js @@ -0,0 +1,65 @@ +// 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. + +function s(v) { + v.x = 1; +} + +function c(p) { + return {__proto__: p}; +} + +var p = {}; + +// Make p the last prototype in the chain. +p.__proto__ = null; + +var o1 = c(p); +var o2 = c(p); +var o3 = c(p); +var o4 = c(p); + +// Make y go to slow mode. +// Do this after using p as prototype, since using an object as prototype kicks +// it back into fast mode. +p.y = 1; +delete p.y; + +// Initialize the store IC. +s(o1); +s(o2); + +// Do something with x in slow-mode p. +Object.defineProperty(p, "x", { writable: false, value: 5 }); + +// Verify that directly setting x fails. +o3.x = 10; +assertEquals(5, o3.x); + +// Verify that setting x through the IC fails. +s(o4); +assertEquals(5, o4.x); diff --git a/deps/v8/test/mjsunit/regress/readonly1.js b/deps/v8/test/mjsunit/regress/readonly1.js new file mode 100644 index 000000000..366f432fb --- /dev/null +++ b/deps/v8/test/mjsunit/regress/readonly1.js @@ -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. + +function s(v) { + v.x = 1; +} + +function s_strict(v) { + "use strict"; + v.x = 1; +} + +function c(p) { + return {__proto__: p}; +} + +var p = {}; + +var o1 = c(p); +var o2 = c(p); +var o3 = c(p); +var o4 = c(p); + +// Make p go slow. +// Do this after using p as prototype, since using an object as prototype kicks +// it back into fast mode. +p.y = 1; +delete p.y; +p.x = 5; + +// Initialize the store IC. +s(o1); +s(o2); +s_strict(o1); +s_strict(o2); + +// Make x non-writable. +Object.defineProperty(p, "x", { writable: false }); + +// Verify that direct setting fails. +o3.x = 20; +assertEquals(5, o3.x); + +// Verify that setting through the IC fails. +s(o4); +assertEquals(5, o4.x); +assertThrows("s_strict(o4);", TypeError); diff --git a/deps/v8/test/mjsunit/regress/readonly2.js b/deps/v8/test/mjsunit/regress/readonly2.js new file mode 100644 index 000000000..4e539250d --- /dev/null +++ b/deps/v8/test/mjsunit/regress/readonly2.js @@ -0,0 +1,62 @@ +// 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. + +Object.defineProperty(this, "x", { writable:true }); + +function s(v) { + v.x = 1; +} + +function s_strict(v) { + "use strict"; + v.x = 1; +} + +function c(p) { + return {__proto__: p}; +} + +var o1 = c(this); +var o2 = c(this); + +// Initialize the store IC. +s(c(this)); +s(c(this)); +s_strict(c(this)); +s_strict(c(this)); + +// Make x non-writable. +Object.defineProperty(this, "x", { writable:false, value:5 }); + +// Verify that direct setting fails. +o1.x = 20; +assertEquals(5, o1.x); + +// Verify that setting through the IC fails. +s(o2); +assertEquals(5, o2.x); +assertThrows("s_strict(o2);", TypeError); diff --git a/deps/v8/test/mjsunit/regress/readonly3.js b/deps/v8/test/mjsunit/regress/readonly3.js new file mode 100644 index 000000000..f81979d27 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/readonly3.js @@ -0,0 +1,65 @@ +// 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.x = 0; + +var p = {}; +Object.defineProperty(p, "x", {writable:false, value:5}); +this.__proto__ = p; + +function s(v) { + v.x = 1; +} + +function s_strict(v) { + "use strict"; + v.x = 1; +} + +function c(p) { + return {__proto__: p}; +} + +var o1 = c(this); +var o2 = c(this); + +// Initialize the store IC. +s(c(this)); +s(c(this)); +s_strict(c(this)); +s_strict(c(this)); + +delete this.x; + +// Verify that direct setting fails. +o1.x = 20; +assertEquals(5, o1.x); + +// Verify that setting through the IC fails. +s(o2); +assertEquals(5, o2.x); +assertThrows("s_strict(o2);", TypeError); diff --git a/deps/v8/test/mjsunit/regress/readonly4.js b/deps/v8/test/mjsunit/regress/readonly4.js new file mode 100644 index 000000000..b2fde2953 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/readonly4.js @@ -0,0 +1,74 @@ +// 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. + +var slow = {}; +var p = {}; + +slow.__proto__ = p; +slow.x = 10; +slow.y = 10; +Object.defineProperty(p, "x", {writable:false, value:5}); + +function c(p) { + return {__proto__: p}; +} + +function s(v) { + return v.x = 1; +} + +function s_strict(v) { + "use strict"; + v.x = 1; +} + +var o1 = c(slow); +var o2 = c(slow); +var o1_strict = c(slow); +var o2_strict = c(slow); +var o3 = c(slow); +var o4 = c(slow); + +// Make s slow. +// Do this after using slow as prototype, since using an object as prototype +// kicks it back into fast mode. +delete slow.y; + +s(o1); +s(o2); +s_strict(o1_strict); +s_strict(o2_strict); + +delete slow.x; +// Directly setting x should fail. +o3.x = 20 +assertEquals(5, o3.x); + +// Setting x through IC should fail. +s(o4); +assertEquals(5, o4.x); +assertThrows("s_strict(o4);", TypeError); diff --git a/deps/v8/test/mjsunit/regress/regress-105.js b/deps/v8/test/mjsunit/regress/regress-105.js new file mode 100644 index 000000000..9a4d5c474 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-105.js @@ -0,0 +1,44 @@ +// 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. + +var custom_valueOf = function() { + assertEquals(Number, custom_valueOf.caller); + return 2; +} + +var custom_toString = function() { + assertEquals(String, custom_toString.caller); + return "I used to be an adventurer like you"; +} + +var object = {}; +object.valueOf = custom_valueOf; +object.toString = custom_toString; + +assertEquals(2, Number(object)); +assertEquals('I', String(object)[0]); + diff --git a/deps/v8/test/mjsunit/regress/regress-166379.js b/deps/v8/test/mjsunit/regress/regress-166379.js index 2cda61182..b19afbdde 100644 --- a/deps/v8/test/mjsunit/regress/regress-166379.js +++ b/deps/v8/test/mjsunit/regress/regress-166379.js @@ -36,3 +36,4 @@ assertEquals(1, mod(3, 2)); // Surprise mod with overflow. assertEquals(-Infinity, 1/mod(-2147483648, -1)); + diff --git a/deps/v8/test/mjsunit/regress/regress-201590.js b/deps/v8/test/mjsunit/regress/regress-201590.js new file mode 100644 index 000000000..0e7ba5723 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-201590.js @@ -0,0 +1,66 @@ +// 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. + +// Flags: --allow-natives-syntax + +var gdpRatio = 16/9; + +function Foo(initialX, initialY, initialScale, initialMapHeight) { + this.ORIGIN = { x: initialX, y: initialY }; + this.scale = initialScale; + this.mapHeight = initialMapHeight; +} + +Foo.prototype.bar = function (x, y, xOffset, yOffset) { + var tileHeight = 64 * 0.25 * this.scale, + tileWidth = 128 * 0.25 * this.scale, + xOffset = xOffset * 0.5 || 0, + yOffset = yOffset * 0.5 || 0; + var xPos = ((xOffset) * gdpRatio) + this.ORIGIN.x * this.scale - + ((y * tileWidth ) * gdpRatio) + ((x * tileWidth ) * gdpRatio); + var yPos = ((yOffset) * gdpRatio) + this.ORIGIN.y * this.scale + + ((y * tileHeight) * gdpRatio) + ((x * tileHeight) * gdpRatio); + xPos = xPos - Math.round(((tileWidth) * gdpRatio)) + + this.mapHeight * Math.round(((tileWidth) * gdpRatio)); + return { + x: Math.floor(xPos), + y: Math.floor(yPos) + }; +} + +var f = new Foo(10, 20, 2.5, 400); + +function baz() { + var b = f.bar(1.1, 2.2, 3.3, 4.4); + assertEquals(56529, b.x); + assertEquals(288, b.y); +} + +baz(); +baz(); +%OptimizeFunctionOnNextCall(Foo.prototype.bar); +baz(); diff --git a/deps/v8/test/mjsunit/regress/regress-2374.js b/deps/v8/test/mjsunit/regress/regress-2374.js index b12e5f28c..b333720ac 100644 --- a/deps/v8/test/mjsunit/regress/regress-2374.js +++ b/deps/v8/test/mjsunit/regress/regress-2374.js @@ -31,3 +31,4 @@ var obj = JSON.parse(msg); var obj2 = JSON.parse(msg); assertEquals(JSON.stringify(obj), JSON.stringify(obj2)); +assertEquals(JSON.stringify(obj, null, 0), JSON.stringify(obj2));
\ No newline at end of file diff --git a/deps/v8/test/mjsunit/regress/regress-2419.js b/deps/v8/test/mjsunit/regress/regress-2419.js index 4ffafbe6e..9cd453a58 100644 --- a/deps/v8/test/mjsunit/regress/regress-2419.js +++ b/deps/v8/test/mjsunit/regress/regress-2419.js @@ -34,3 +34,4 @@ var b = {0: 5, 1: 4, 2: 3, 3: 2, 4: 1, 5: 0, length: 6}; Object.freeze(b); Array.prototype.sort.call(b); assertPropertiesEqual({0: 5, 1: 4, 2: 3, 3: 2, 4: 1, 5: 0, length: 6}, b); + diff --git a/deps/v8/test/mjsunit/regress/regress-2438.js b/deps/v8/test/mjsunit/regress/regress-2438.js index 7be7e7168..3f4fd7df5 100644 --- a/deps/v8/test/mjsunit/regress/regress-2438.js +++ b/deps/v8/test/mjsunit/regress/regress-2438.js @@ -49,3 +49,4 @@ testSideEffects("zzzz", /a/); testSideEffects("zzzz", /a/g); testSideEffects("xaxa", /a/); testSideEffects("xaxa", /a/g); + diff --git a/deps/v8/test/mjsunit/regress/regress-2444.js b/deps/v8/test/mjsunit/regress/regress-2444.js index 41b6a95e7..8fb8d8b52 100644 --- a/deps/v8/test/mjsunit/regress/regress-2444.js +++ b/deps/v8/test/mjsunit/regress/regress-2444.js @@ -116,3 +116,5 @@ assertEquals(0, object_factory(1, 0, [1, 0, 0]), object_factory(2, 1, [1, 1, 0]))); assertFlags([1, 1, 1]); + + diff --git a/deps/v8/test/mjsunit/regress/regress-2451.js b/deps/v8/test/mjsunit/regress/regress-2451.js index cc087e75e..465e4e68c 100644 --- a/deps/v8/test/mjsunit/regress/regress-2451.js +++ b/deps/v8/test/mjsunit/regress/regress-2451.js @@ -38,3 +38,4 @@ f(); %OptimizeFunctionOnNextCall(f); f(); assertTrue(%GetOptimizationStatus(f) != 2); + diff --git a/deps/v8/test/mjsunit/regress/regress-2564.js b/deps/v8/test/mjsunit/regress/regress-2564.js new file mode 100644 index 000000000..1d7cdaeae --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2564.js @@ -0,0 +1,122 @@ +// 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. + +var o = [ function f0() { throw new Error(); }, + function f1() { o[0](); }, + function f2() { o[1](); }, + function f3() { o[2](); } ]; + +Error.prepareStackTrace = function(error, frames) { + Error.prepareStackTrace = undefined; // Prevent recursion. + try { + assertEquals(5, frames.length); + // Don't check the last frame since that's the top-level code. + for (var i = 0; i < frames.length - 1; i++) { + assertEquals(o[i], frames[i].getFunction()); + assertEquals(o, frames[i].getThis()); + // Private fields are no longer accessible. + assertEquals(undefined, frames[i].receiver); + assertEquals(undefined, frames[i].fun); + assertEquals(undefined, frames[i].pos); + } + return "success"; + } catch (e) { + return "fail"; + } +} + +try { + o[3](); +} catch (e) { + assertEquals("success", e.stack); +}; + + +var o = [ function f0() { throw new Error(); }, + function f1() { o[0](); }, + function f2() { "use strict"; o[1](); }, + function f3() { o[2](); } ]; + +Error.prepareStackTrace = function(error, frames) { + Error.prepareStackTrace = undefined; // Prevent recursion. + try { + assertEquals(5, frames.length); + for (var i = 0; i < 2; i++) { + // The first two frames are still classic mode. + assertEquals(o[i], frames[i].getFunction()); + assertEquals(o, frames[i].getThis()); + } + for (var i = 2; i < frames.length; i++) { + // The rest are poisoned by the first strict mode function. + assertEquals(undefined, frames[i].getFunction()); + assertEquals(undefined, frames[i].getThis()); + } + for (var i = 0; i < frames.length - 1; i++) { + // Function name remains accessible. + assertEquals("f"+i, frames[i].getFunctionName()); + } + return "success"; + } catch (e) { + return e; + } +} + +try { + o[3](); +} catch (e) { + assertEquals("success", e.stack); +}; + + +var o = [ function f0() { "use strict"; throw new Error(); }, + function f1() { o[0](); }, + function f2() { o[1](); }, + function f3() { o[2](); } ]; + +Error.prepareStackTrace = function(error, frames) { + Error.prepareStackTrace = undefined; // Prevent recursion. + try { + assertEquals(5, frames.length); + for (var i = 0; i < frames.length; i++) { + // The rest are poisoned by the first strict mode function. + assertEquals(undefined, frames[i].getFunction()); + assertEquals(undefined, frames[i].getThis()); + if (i < frames.length - 1) { // Function name remains accessible. + assertEquals("f"+i, frames[i].getFunctionName()); + } + } + return "success"; + } catch (e) { + return e; + } +} + +try { + o[3](); +} catch (e) { + assertEquals("success", e.stack); +}; diff --git a/deps/v8/test/mjsunit/regress/regress-2570.js b/deps/v8/test/mjsunit/regress/regress-2570.js index f9060e8c0..4e32a21e4 100644 --- a/deps/v8/test/mjsunit/regress/regress-2570.js +++ b/deps/v8/test/mjsunit/regress/regress-2570.js @@ -29,3 +29,4 @@ var o = ["\u56e7", // Switch JSON stringifier to two-byte mode. "\u00e6"]; // Latin-1 character. assertEquals('["\u56e7","\u00e6"]', JSON.stringify(o)); +assertEquals('["\u56e7","\u00e6"]', JSON.stringify(o, null, 0));
\ No newline at end of file diff --git a/deps/v8/test/mjsunit/regress/regress-2593.js b/deps/v8/test/mjsunit/regress/regress-2593.js new file mode 100644 index 000000000..b51b41c27 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2593.js @@ -0,0 +1,61 @@ +// 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. + +// Flags: --expose_gc + +p1 = { }; +p2 = { }; +p3 = { x : 1 }; +p2.__proto__ = p3 +p1.__proto__ = p2 + +// Normalize p1. +p1.z = 1 +delete p1.z + +// Make sure all objects are in old space. +for (var i = 0; i < 10; i++) gc(); + +function f2() { + p2.x; +} + +function f1() { + return p1.x; +} + +// Create load stub in p2. +for (var i = 0; i < 10; i++) f2(); + +// Create load stub in p2 for p1. +for (var i = 0; i < 10; i++) f1(); + +assertEquals(1, f1()); + +p2.x = 2; + +assertEquals(2, f1()); diff --git a/deps/v8/test/mjsunit/regress/regress-2596.js b/deps/v8/test/mjsunit/regress/regress-2596.js new file mode 100644 index 000000000..1d327fe0f --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2596.js @@ -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. + +// Flags: --allow-natives-syntax + +var bytes = new Uint8Array([ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]); // kHoleNaN +var doubles = new Float64Array(bytes.buffer); +assertTrue(isNaN(doubles[0])); + +var prototype = [2.5, 2.5]; +var array = [3.5, 3.5]; +array.__proto__ = prototype; +assertTrue(%HasFastDoubleElements(array)); + +function boom(index) { + array[index] = doubles[0]; + return array[index]; +} + +assertTrue(isNaN(boom(0))); +assertTrue(isNaN(boom(0))); +assertTrue(isNaN(boom(0))); + +// Test hydrogen +%OptimizeFunctionOnNextCall(boom); +assertTrue(isNaN(boom(0))); +assertTrue(isNaN(boom(0))); +assertTrue(isNaN(boom(0))); + + + diff --git a/deps/v8/test/mjsunit/regress/regress-753.js b/deps/v8/test/mjsunit/regress/regress-753.js index 6a6d87bb0..4621de6ba 100644 --- a/deps/v8/test/mjsunit/regress/regress-753.js +++ b/deps/v8/test/mjsunit/regress/regress-753.js @@ -32,5 +32,5 @@ // See: http://code.google.com/p/v8/issues/detail?id=753 var obj = {a1: {b1: [1,2,3,4], b2: {c1: 1, c2: 2}},a2: 'a2'}; -assertEquals(JSON.stringify(obj,null, 5.99999), JSON.stringify(obj,null, 5)); +assertEquals(JSON.stringify(obj, null, 5.99999), JSON.stringify(obj, null, 5)); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-146910.js b/deps/v8/test/mjsunit/regress/regress-crbug-146910.js index 1b2a60af7..120f80973 100644 --- a/deps/v8/test/mjsunit/regress/regress-crbug-146910.js +++ b/deps/v8/test/mjsunit/regress/regress-crbug-146910.js @@ -1,4 +1,4 @@ -// Copyright 2013 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -25,9 +25,14 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -assertEquals(String.fromCharCode(97, 220, 256), 'a' + '\u00DC' + '\u0100'); -assertEquals(String.fromCharCode(97, 220, 256), 'a\u00DC\u0100'); +var x = []; +assertSame(0, x.length); +assertSame(undefined, x[0]); -assertEquals(['a', 'b', '\xdc'], ['b', '\xdc', 'a'].sort()); -assertEquals(['\xfc\xdc', '\xfc'], new RegExp('(\xdc)\\1', 'i').exec('\xfc\xdc')); +Object.defineProperty(x, '0', { value: 7, configurable: false }); +assertSame(1, x.length); +assertSame(7, x[0]); +x.length = 0; +assertSame(1, x.length); +assertSame(7, x[0]); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-158185.js b/deps/v8/test/mjsunit/regress/regress-crbug-158185.js index 5cb5900c8..99f19c72f 100644 --- a/deps/v8/test/mjsunit/regress/regress-crbug-158185.js +++ b/deps/v8/test/mjsunit/regress/regress-crbug-158185.js @@ -36,3 +36,4 @@ assertEquals("12A", assertEquals(1, JSON.parse('{"0":1}')[0]); assertEquals(undefined, JSON.parse('{"00":1}')[0]); + diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-171715.js b/deps/v8/test/mjsunit/regress/regress-crbug-171715.js new file mode 100644 index 000000000..040c381e3 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-171715.js @@ -0,0 +1,87 @@ +// 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. + +// Flags: --expose-debug-as debug + +Debug = debug.Debug + +var error = null; +var test = 0; + +function check_v(expected, exec_state, frame_id) { + assertEquals(expected, exec_state.frame(frame_id).evaluate('v').value()); +} + +function listener(event, exec_state, event_data, data) { + try { + if (event != Debug.DebugEvent.Break) return; + test++; + if (test == 1) { + check_v('inner0', exec_state, 0); + check_v('inner0', exec_state, 1); + check_v('outer', exec_state, 2); + assertArrayEquals(["a", "b", "c"], + exec_state.frame(0).evaluate('arguments').value()); + } else if (test == 2) { + check_v('inner1', exec_state, 0); + check_v('inner1', exec_state, 1); + check_v('outer', exec_state, 2); + assertArrayEquals(["a", "b", "c"], + exec_state.frame(0).evaluate('arguments').value()); + } else { + assertEquals(3, test); + check_v('inner2', exec_state, 0); + check_v('inner1', exec_state, 1); + check_v('inner1', exec_state, 2); + check_v('outer', exec_state, 3); + assertArrayEquals(["x", "y", "z"], + exec_state.frame(0).evaluate('arguments').value()); + assertArrayEquals(["a", "b", "c"], + exec_state.frame(1).evaluate('arguments').value()); + } + } catch (e) { + error = e; + } +}; + +Debug.setListener(listener); + +var v = 'outer'; +(function() { // Test 1 and 2 + var v = 'inner0'; + eval("debugger; var v = 'inner1'; debugger;"); + assertEquals('inner1', v); // Overwritten by local eval. +})("a", "b", "c"); +assertNull(error); + +(function() { // Test 3 + var v = 'inner0'; // Local eval overwrites this value. + eval("var v = 'inner1'; " + + "(function() { var v = 'inner2'; debugger; })('x', 'y', 'z');"); + assertEquals('inner1', v); // Overwritten by local eval. +})("a", "b", "c"); +assertNull(error); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-178790.js b/deps/v8/test/mjsunit/regress/regress-crbug-178790.js index 25cc96b85..57071eaa0 100644 --- a/deps/v8/test/mjsunit/regress/regress-crbug-178790.js +++ b/deps/v8/test/mjsunit/regress/regress-crbug-178790.js @@ -49,3 +49,4 @@ for (var i = 0; i < 1000; i++) { r3 = "(" + r3 + ")a"; } "test".match(RegExp(r3)); + diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-217858.js b/deps/v8/test/mjsunit/regress/regress-crbug-217858.js new file mode 100644 index 000000000..8563e07ee --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-217858.js @@ -0,0 +1,40 @@ +// 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. + +// Flags: --allow-natives-syntax + +var r = /r/; +var a = ""; +function f() { + %OptimizeFunctionOnNextCall(f, "osr"); + for (var i = 0; i < 1000000; i++) { + a += i.toString(); + r[r] = function() {}; + } +} + +f(); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-222893.js b/deps/v8/test/mjsunit/regress/regress-crbug-222893.js new file mode 100644 index 000000000..d5baa7b25 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-222893.js @@ -0,0 +1,64 @@ +// 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. + +// Flags: --expose-debug-as debug + +Debug = debug.Debug + +var error = null; +var array = ["a", "b", "c"]; + +function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + assertArrayEquals(array, + exec_state.frame(0).evaluate('arguments').value()); + } + } catch (e) { + error = e; + } +}; + +Debug.setListener(listener); + + +function f(a, b) { + arguments; + debugger; // Arguments object is already materialized. +} + +f.apply(this, array); +f("a", "b", "c"); +assertNull(error); + +function g(a, b) { + debugger; // Arguments object is not yet materialized. +} +g.apply(this, array); +g("a", "b", "c"); +assertNull(error); + diff --git a/deps/v8/test/mjsunit/regress/regress-json-stringify-gc.js b/deps/v8/test/mjsunit/regress/regress-json-stringify-gc.js index 46c3dbf12..c0a71bf4a 100644 --- a/deps/v8/test/mjsunit/regress/regress-json-stringify-gc.js +++ b/deps/v8/test/mjsunit/regress/regress-json-stringify-gc.js @@ -38,3 +38,4 @@ for (var i = 0; i < 10000; i++) a.push(new_space_string); json1 = JSON.stringify(a); json2 = JSON.stringify(a); assertTrue(json1 == json2, "GC caused JSON.stringify to fail."); + diff --git a/deps/v8/test/mjsunit/regress/regress-latin-1.js b/deps/v8/test/mjsunit/regress/regress-latin-1.js index a988ebd36..e7f31366c 100644 --- a/deps/v8/test/mjsunit/regress/regress-latin-1.js +++ b/deps/v8/test/mjsunit/regress/regress-latin-1.js @@ -29,6 +29,7 @@ assertEquals(String.fromCharCode(97, 220, 256), 'a' + '\u00DC' + '\u0100'); assertEquals(String.fromCharCode(97, 220, 256), 'a\u00DC\u0100'); assertEquals(0x80, JSON.stringify("\x80").charCodeAt(1)); +assertEquals(0x80, JSON.stringify("\x80", 0, null).charCodeAt(1)); assertEquals(['a', 'b', '\xdc'], ['b', '\xdc', 'a'].sort()); diff --git a/deps/v8/test/mjsunit/regress/setter.js b/deps/v8/test/mjsunit/regress/setter.js new file mode 100644 index 000000000..e3a8000f2 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/setter.js @@ -0,0 +1,66 @@ +// 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. + +function s(v) { + v.x = 1; +} + +function c(p) { + return {__proto__: p}; +} + +var p = {}; + +var o1 = c(p); +var o2 = c(p); +var o3 = c(p); +var o4 = c(p); +var o5 = c(p); + +// Initialize the store IC. +s(o1); +s(o2); + +// Install a setter on p.x +var count = 0; +Object.defineProperty(p, "x", { + set: function(x) { + count += 1; + } +}); + +// Verify that the setter was called directly. +o3.x = 20; +assertEquals(1, count); + +// Verify that monomorphic prototype failure is triggered in the IC. +s(o4); +assertEquals(2, count); + +// Verify that the newly installed IC is correct. +s(o5); +assertEquals(3, count); diff --git a/deps/v8/test/mjsunit/shift-for-integer-div.js b/deps/v8/test/mjsunit/shift-for-integer-div.js index d3c9d2b49..0fe126229 100644 --- a/deps/v8/test/mjsunit/shift-for-integer-div.js +++ b/deps/v8/test/mjsunit/shift-for-integer-div.js @@ -56,3 +56,4 @@ for (var i = 0; i < 10000; i++) { var min_int = -(0x7FFFFFFF)-1; assertEquals(-min_int, divn1(min_int)); + diff --git a/deps/v8/test/mjsunit/string-natives.js b/deps/v8/test/mjsunit/string-natives.js index 12fa65dcb..b1ec87542 100644 --- a/deps/v8/test/mjsunit/string-natives.js +++ b/deps/v8/test/mjsunit/string-natives.js @@ -69,3 +69,4 @@ test(); test(); %OptimizeFunctionOnNextCall(test); test(); + diff --git a/deps/v8/tools/grokdump.py b/deps/v8/tools/grokdump.py index 7daad21ee..f3ae8a22b 100755 --- a/deps/v8/tools/grokdump.py +++ b/deps/v8/tools/grokdump.py @@ -830,82 +830,82 @@ class MinidumpReader(object): # }; # static P p; INSTANCE_TYPES = { - 64: "SYMBOL_TYPE", - 68: "ASCII_SYMBOL_TYPE", - 65: "CONS_SYMBOL_TYPE", - 69: "CONS_ASCII_SYMBOL_TYPE", - 66: "EXTERNAL_SYMBOL_TYPE", - 74: "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE", - 70: "EXTERNAL_ASCII_SYMBOL_TYPE", - 82: "SHORT_EXTERNAL_SYMBOL_TYPE", - 90: "SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE", - 86: "SHORT_EXTERNAL_ASCII_SYMBOL_TYPE", 0: "STRING_TYPE", 4: "ASCII_STRING_TYPE", 1: "CONS_STRING_TYPE", 5: "CONS_ASCII_STRING_TYPE", 3: "SLICED_STRING_TYPE", 2: "EXTERNAL_STRING_TYPE", - 10: "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE", 6: "EXTERNAL_ASCII_STRING_TYPE", + 10: "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE", 18: "SHORT_EXTERNAL_STRING_TYPE", - 26: "SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE", 22: "SHORT_EXTERNAL_ASCII_STRING_TYPE", - 6: "PRIVATE_EXTERNAL_ASCII_STRING_TYPE", - 128: "MAP_TYPE", - 129: "CODE_TYPE", - 130: "ODDBALL_TYPE", - 131: "JS_GLOBAL_PROPERTY_CELL_TYPE", - 132: "HEAP_NUMBER_TYPE", - 133: "FOREIGN_TYPE", - 134: "BYTE_ARRAY_TYPE", - 135: "FREE_SPACE_TYPE", - 136: "EXTERNAL_BYTE_ARRAY_TYPE", - 137: "EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE", - 138: "EXTERNAL_SHORT_ARRAY_TYPE", - 139: "EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE", - 140: "EXTERNAL_INT_ARRAY_TYPE", - 141: "EXTERNAL_UNSIGNED_INT_ARRAY_TYPE", - 142: "EXTERNAL_FLOAT_ARRAY_TYPE", - 144: "EXTERNAL_PIXEL_ARRAY_TYPE", - 146: "FILLER_TYPE", - 147: "DECLARED_ACCESSOR_DESCRIPTOR_TYPE", - 148: "DECLARED_ACCESSOR_INFO_TYPE", - 149: "EXECUTABLE_ACCESSOR_INFO_TYPE", - 150: "ACCESSOR_PAIR_TYPE", - 151: "ACCESS_CHECK_INFO_TYPE", - 152: "INTERCEPTOR_INFO_TYPE", - 153: "CALL_HANDLER_INFO_TYPE", - 154: "FUNCTION_TEMPLATE_INFO_TYPE", - 155: "OBJECT_TEMPLATE_INFO_TYPE", - 156: "SIGNATURE_INFO_TYPE", - 157: "TYPE_SWITCH_INFO_TYPE", - 158: "ALLOCATION_SITE_INFO_TYPE", - 159: "SCRIPT_TYPE", - 160: "CODE_CACHE_TYPE", - 161: "POLYMORPHIC_CODE_CACHE_TYPE", - 162: "TYPE_FEEDBACK_INFO_TYPE", - 163: "ALIASED_ARGUMENTS_ENTRY_TYPE", - 166: "FIXED_ARRAY_TYPE", - 145: "FIXED_DOUBLE_ARRAY_TYPE", - 167: "SHARED_FUNCTION_INFO_TYPE", - 168: "JS_MESSAGE_OBJECT_TYPE", - 171: "JS_VALUE_TYPE", - 172: "JS_DATE_TYPE", - 173: "JS_OBJECT_TYPE", - 174: "JS_CONTEXT_EXTENSION_OBJECT_TYPE", - 175: "JS_MODULE_TYPE", - 176: "JS_GLOBAL_OBJECT_TYPE", - 177: "JS_BUILTINS_OBJECT_TYPE", - 178: "JS_GLOBAL_PROXY_TYPE", - 179: "JS_ARRAY_TYPE", - 170: "JS_PROXY_TYPE", - 182: "JS_WEAK_MAP_TYPE", - 183: "JS_REGEXP_TYPE", - 184: "JS_FUNCTION_TYPE", - 169: "JS_FUNCTION_PROXY_TYPE", - 164: "DEBUG_INFO_TYPE", - 165: "BREAK_POINT_INFO_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_REGEXP_TYPE", + 185: "JS_FUNCTION_TYPE", + 170: "JS_FUNCTION_PROXY_TYPE", + 165: "DEBUG_INFO_TYPE", + 166: "BREAK_POINT_INFO_TYPE", } @@ -931,86 +931,87 @@ INSTANCE_TYPES = { # } # printf("}\n"); KNOWN_MAPS = { - 0x08081: (134, "ByteArrayMap"), - 0x080a9: (128, "MetaMap"), - 0x080d1: (130, "OddballMap"), - 0x080f9: (68, "AsciiSymbolMap"), - 0x08121: (166, "FixedArrayMap"), - 0x08149: (132, "HeapNumberMap"), - 0x08171: (135, "FreeSpaceMap"), - 0x08199: (146, "OnePointerFillerMap"), - 0x081c1: (146, "TwoPointerFillerMap"), - 0x081e9: (131, "GlobalPropertyCellMap"), - 0x08211: (167, "SharedFunctionInfoMap"), - 0x08239: (4, "AsciiStringMap"), - 0x08261: (166, "NativeContextMap"), - 0x08289: (129, "CodeMap"), - 0x082b1: (166, "ScopeInfoMap"), - 0x082d9: (166, "FixedCOWArrayMap"), - 0x08301: (145, "FixedDoubleArrayMap"), - 0x08329: (166, "HashTableMap"), + 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: (64, "SymbolMap"), + 0x08379: (4, "AsciiStringMap"), 0x083a1: (1, "ConsStringMap"), 0x083c9: (5, "ConsAsciiStringMap"), 0x083f1: (3, "SlicedStringMap"), 0x08419: (7, "SlicedAsciiStringMap"), - 0x08441: (65, "ConsSymbolMap"), - 0x08469: (69, "ConsAsciiSymbolMap"), - 0x08491: (66, "ExternalSymbolMap"), - 0x084b9: (74, "ExternalSymbolWithAsciiDataMap"), - 0x084e1: (70, "ExternalAsciiSymbolMap"), - 0x08509: (2, "ExternalStringMap"), - 0x08531: (10, "ExternalStringWithAsciiDataMap"), - 0x08559: (6, "ExternalAsciiStringMap"), - 0x08581: (82, "ShortExternalSymbolMap"), - 0x085a9: (90, "ShortExternalSymbolWithAsciiDataMap"), - 0x085d1: (86, "ShortExternalAsciiSymbolMap"), - 0x085f9: (18, "ShortExternalStringMap"), - 0x08621: (26, "ShortExternalStringWithAsciiDataMap"), - 0x08649: (22, "ShortExternalAsciiStringMap"), - 0x08671: (0, "UndetectableStringMap"), - 0x08699: (4, "UndetectableAsciiStringMap"), - 0x086c1: (144, "ExternalPixelArrayMap"), - 0x086e9: (136, "ExternalByteArrayMap"), - 0x08711: (137, "ExternalUnsignedByteArrayMap"), - 0x08739: (138, "ExternalShortArrayMap"), - 0x08761: (139, "ExternalUnsignedShortArrayMap"), - 0x08789: (140, "ExternalIntArrayMap"), - 0x087b1: (141, "ExternalUnsignedIntArrayMap"), - 0x087d9: (142, "ExternalFloatArrayMap"), - 0x08801: (143, "ExternalDoubleArrayMap"), - 0x08829: (166, "NonStrictArgumentsElementsMap"), - 0x08851: (166, "FunctionContextMap"), - 0x08879: (166, "CatchContextMap"), - 0x088a1: (166, "WithContextMap"), - 0x088c9: (166, "BlockContextMap"), - 0x088f1: (166, "ModuleContextMap"), - 0x08919: (166, "GlobalContextMap"), - 0x08941: (168, "JSMessageObjectMap"), - 0x08969: (133, "ForeignMap"), - 0x08991: (173, "NeanderMap"), - 0x089b9: (158, "AllocationSiteInfoMap"), - 0x089e1: (161, "PolymorphicCodeCacheMap"), - 0x08a09: (159, "ScriptMap"), - 0x08a31: (173, ""), - 0x08a59: (173, "ExternalMap"), - 0x08a81: (147, "DeclaredAccessorDescriptorMap"), - 0x08aa9: (148, "DeclaredAccessorInfoMap"), - 0x08ad1: (149, "ExecutableAccessorInfoMap"), - 0x08af9: (150, "AccessorPairMap"), - 0x08b21: (151, "AccessCheckInfoMap"), - 0x08b49: (152, "InterceptorInfoMap"), - 0x08b71: (153, "CallHandlerInfoMap"), - 0x08b99: (154, "FunctionTemplateInfoMap"), - 0x08bc1: (155, "ObjectTemplateInfoMap"), - 0x08be9: (156, "SignatureInfoMap"), - 0x08c11: (157, "TypeSwitchInfoMap"), - 0x08c39: (160, "CodeCacheMap"), - 0x08c61: (162, "TypeFeedbackInfoMap"), - 0x08c89: (163, "AliasedArgumentsEntryMap"), - 0x08cb1: (164, "DebugInfoMap"), - 0x08cd9: (165, "BreakPointInfoMap"), + 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"), } @@ -1932,7 +1933,7 @@ class InspectionShell(cmd.Cmd): Print a descriptor array in a readable format. """ start = int(address, 16) - if ((start & 1) == 1): start = start + 1 + if ((start & 1) == 1): start = start - 1 DescriptorArray(FixedArray(self.heap, None, start)).Print(Printer()) def do_do_map(self, address): diff --git a/deps/v8/tools/gyp/v8.gyp b/deps/v8/tools/gyp/v8.gyp index 2d6eaf9d0..b11755322 100644 --- a/deps/v8/tools/gyp/v8.gyp +++ b/deps/v8/tools/gyp/v8.gyp @@ -797,7 +797,8 @@ '../../src/symbol.js', '../../src/proxy.js', '../../src/collection.js', - '../../src/object-observe.js' + '../../src/object-observe.js', + '../../src/typedarray.js' ], }, 'actions': [ |