Implement circular queues for the C++ version of CPU profiler.
authormikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 17 Mar 2010 12:25:10 +0000 (12:25 +0000)
committermikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 17 Mar 2010 12:25:10 +0000 (12:25 +0000)
Circular queues serve as a transport for communicating between
VM, stack sampler and analyzer threads. Logging requirements
for VM and stack sampler are completely different, that's why
I introduced two different versions of CQs.

Review URL: http://codereview.chromium.org/1047002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4159 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

15 files changed:
src/SConscript
src/circular-queue-inl.h [new file with mode: 0644]
src/circular-queue.cc [new file with mode: 0644]
src/circular-queue.h [new file with mode: 0644]
src/platform.h
test/cctest/SConscript
test/cctest/test-circular-queue.cc [new file with mode: 0644]
tools/gyp/v8.gyp
tools/v8.xcodeproj/project.pbxproj
tools/visual_studio/v8_base.vcproj
tools/visual_studio/v8_base_arm.vcproj
tools/visual_studio/v8_base_x64.vcproj
tools/visual_studio/v8_cctest.vcproj
tools/visual_studio/v8_cctest_arm.vcproj
tools/visual_studio/v8_cctest_x64.vcproj

index ce41cb0..4e474f4 100755 (executable)
@@ -43,6 +43,7 @@ SOURCES = {
     bootstrapper.cc
     builtins.cc
     checks.cc
+    circular-queue.cc
     code-stubs.cc
     codegen.cc
     compilation-cache.cc
diff --git a/src/circular-queue-inl.h b/src/circular-queue-inl.h
new file mode 100644 (file)
index 0000000..ffe8fb0
--- /dev/null
@@ -0,0 +1,101 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_CIRCULAR_BUFFER_INL_H_
+#define V8_CIRCULAR_BUFFER_INL_H_
+
+#include "circular-queue.h"
+
+namespace v8 {
+namespace internal {
+
+
+template<typename Record>
+CircularQueue<Record>::CircularQueue(int desired_buffer_size_in_bytes)
+    : buffer_(NewArray<Record>(desired_buffer_size_in_bytes / sizeof(Record))),
+      buffer_end_(buffer_ + desired_buffer_size_in_bytes / sizeof(Record)),
+      enqueue_semaphore_(OS::CreateSemaphore((buffer_end_ - buffer_) - 1)),
+      enqueue_pos_(buffer_),
+      dequeue_pos_(buffer_) {
+  // To be able to distinguish between a full and an empty queue
+  // state, the queue must be capable of containing at least 2
+  // records.
+  ASSERT((buffer_end_ - buffer_) >= 2);
+}
+
+
+template<typename Record>
+CircularQueue<Record>::~CircularQueue() {
+  DeleteArray(buffer_);
+  delete enqueue_semaphore_;
+}
+
+
+template<typename Record>
+void CircularQueue<Record>::Dequeue(Record* rec) {
+  ASSERT(!IsEmpty());
+  *rec = *dequeue_pos_;
+  dequeue_pos_ = Next(dequeue_pos_);
+  // Tell we have a spare record.
+  enqueue_semaphore_->Signal();
+}
+
+
+template<typename Record>
+void CircularQueue<Record>::Enqueue(const Record& rec) {
+  // Wait until we have at least one spare record.
+  enqueue_semaphore_->Wait();
+  ASSERT(Next(enqueue_pos_) != dequeue_pos_);
+  *enqueue_pos_ = rec;
+  enqueue_pos_ = Next(enqueue_pos_);
+}
+
+
+template<typename Record>
+Record* CircularQueue<Record>::Next(Record* curr) {
+  return ++curr != buffer_end_ ? curr : buffer_;
+}
+
+
+void* SamplingCircularQueue::Enqueue() {
+  Cell* enqueue_pos = reinterpret_cast<Cell*>(
+      Thread::GetThreadLocal(producer_key_));
+  WrapPositionIfNeeded(&enqueue_pos);
+  Thread::SetThreadLocal(producer_key_, enqueue_pos + record_size_);
+  return enqueue_pos;
+}
+
+
+void SamplingCircularQueue::WrapPositionIfNeeded(
+    SamplingCircularQueue::Cell** pos) {
+  if (**pos == kEnd) *pos = buffer_;
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_CIRCULAR_BUFFER_INL_H_
diff --git a/src/circular-queue.cc b/src/circular-queue.cc
new file mode 100644 (file)
index 0000000..5f7a33e
--- /dev/null
@@ -0,0 +1,131 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "circular-queue-inl.h"
+
+namespace v8 {
+namespace internal {
+
+
+SamplingCircularQueue::SamplingCircularQueue(int record_size_in_bytes,
+                                             int desired_chunk_size_in_bytes,
+                                             int buffer_size_in_chunks)
+    : record_size_(record_size_in_bytes / sizeof(Cell)),
+      chunk_size_in_bytes_(desired_chunk_size_in_bytes / record_size_in_bytes *
+                        record_size_in_bytes),
+      chunk_size_(chunk_size_in_bytes_ / sizeof(Cell)),
+      buffer_size_(chunk_size_ * buffer_size_in_chunks),
+      // The distance ensures that producer and consumer never step on
+      // each other's chunks and helps eviction of produced data from
+      // the CPU cache (having that chunk size is bigger than the cache.)
+      producer_consumer_distance_(2 * chunk_size_),
+      buffer_(NewArray<Cell>(buffer_size_ + 1)) {
+  ASSERT(buffer_size_in_chunks > 2);
+  // Only need to keep the first cell of a chunk clean.
+  for (int i = 0; i < buffer_size_; i += chunk_size_) {
+    buffer_[i] = kClear;
+  }
+  buffer_[buffer_size_] = kEnd;
+}
+
+
+SamplingCircularQueue::~SamplingCircularQueue() {
+  DeleteArray(buffer_);
+}
+
+
+void SamplingCircularQueue::SetUpProducer() {
+  producer_key_ = Thread::CreateThreadLocalKey();
+  Thread::SetThreadLocal(producer_key_, buffer_);
+}
+
+
+void SamplingCircularQueue::TearDownProducer() {
+  Thread::DeleteThreadLocalKey(producer_key_);
+}
+
+
+void SamplingCircularQueue::SetUpConsumer() {
+  consumer_key_ = Thread::CreateThreadLocalKey();
+  ConsumerPosition* cp = new ConsumerPosition;
+  cp->dequeue_chunk_pos = buffer_;
+  cp->dequeue_chunk_poll_pos = buffer_ + producer_consumer_distance_;
+  cp->dequeue_pos = NULL;
+  Thread::SetThreadLocal(consumer_key_, cp);
+}
+
+
+void SamplingCircularQueue::TearDownConsumer() {
+  delete reinterpret_cast<ConsumerPosition*>(
+      Thread::GetThreadLocal(consumer_key_));
+  Thread::DeleteThreadLocalKey(consumer_key_);
+}
+
+
+void* SamplingCircularQueue::StartDequeue() {
+  ConsumerPosition* cp = reinterpret_cast<ConsumerPosition*>(
+      Thread::GetThreadLocal(consumer_key_));
+  if (cp->dequeue_pos != NULL) {
+    return cp->dequeue_pos;
+  } else {
+    if (*cp->dequeue_chunk_poll_pos != kClear) {
+      cp->dequeue_pos = cp->dequeue_chunk_pos;
+      cp->dequeue_end_pos = cp->dequeue_pos + chunk_size_;
+      return cp->dequeue_pos;
+    } else {
+      return NULL;
+    }
+  }
+}
+
+
+void SamplingCircularQueue::FinishDequeue() {
+  ConsumerPosition* cp = reinterpret_cast<ConsumerPosition*>(
+      Thread::GetThreadLocal(consumer_key_));
+  cp->dequeue_pos += record_size_;
+  if (cp->dequeue_pos < cp->dequeue_end_pos) return;
+  // Move to next chunk.
+  cp->dequeue_pos = NULL;
+  *cp->dequeue_chunk_pos = kClear;
+  cp->dequeue_chunk_pos += chunk_size_;
+  WrapPositionIfNeeded(&cp->dequeue_chunk_pos);
+  cp->dequeue_chunk_poll_pos += chunk_size_;
+  WrapPositionIfNeeded(&cp->dequeue_chunk_poll_pos);
+}
+
+
+void SamplingCircularQueue::FlushResidualRecords() {
+  ConsumerPosition* cp = reinterpret_cast<ConsumerPosition*>(
+      Thread::GetThreadLocal(consumer_key_));
+  // Eliminate producer / consumer distance.
+  cp->dequeue_chunk_poll_pos = cp->dequeue_chunk_pos;
+}
+
+
+} }  // namespace v8::internal
diff --git a/src/circular-queue.h b/src/circular-queue.h
new file mode 100644 (file)
index 0000000..11159e0
--- /dev/null
@@ -0,0 +1,130 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_CIRCULAR_QUEUE_H_
+#define V8_CIRCULAR_QUEUE_H_
+
+namespace v8 {
+namespace internal {
+
+
+// Lock-based blocking circular queue for small records.  Intended for
+// transfer of small records between a single producer and a single
+// consumer. Blocks on enqueue operation if the queue is full.
+template<typename Record>
+class CircularQueue {
+ public:
+  inline explicit CircularQueue(int desired_buffer_size_in_bytes);
+  inline ~CircularQueue();
+
+  INLINE(void Dequeue(Record* rec));
+  INLINE(void Enqueue(const Record& rec));
+  INLINE(bool IsEmpty()) { return enqueue_pos_ == dequeue_pos_; }
+
+ private:
+  INLINE(Record* Next(Record* curr));
+
+  Record* buffer_;
+  Record* const buffer_end_;
+  Semaphore* enqueue_semaphore_;
+  Record* enqueue_pos_;
+  Record* dequeue_pos_;
+
+  DISALLOW_COPY_AND_ASSIGN(CircularQueue);
+};
+
+
+// Lock-free cache-friendly sampling circular queue for large
+// records. Intended for fast transfer of large records between a
+// single producer and a single consumer. If the queue is full,
+// previous unread records are overwritten. The queue is designed with
+// a goal in mind to evade cache lines thrashing by preventing
+// simultaneous reads and writes to adjanced memory locations.
+//
+// IMPORTANT: as a producer never checks for chunks cleanness, it is
+// possible that it can catch up and overwrite a chunk that a consumer
+// is currently reading, resulting in a corrupt record being read.
+class SamplingCircularQueue {
+ public:
+  // Executed on the application thread.
+  SamplingCircularQueue(int record_size_in_bytes,
+                        int desired_chunk_size_in_bytes,
+                        int buffer_size_in_chunks);
+  ~SamplingCircularQueue();
+
+  // Executed on the producer (sampler) or application thread.
+  void SetUpProducer();
+  // Enqueue returns a pointer to a memory location for storing the next
+  // record.
+  INLINE(void* Enqueue());
+  void TearDownProducer();
+
+  // Executed on the consumer (analyzer) thread.
+  void SetUpConsumer();
+  // StartDequeue returns a pointer to a memory location for retrieving
+  // the next record. After the record had been read by a consumer,
+  // FinishDequeue must be called. Until that moment, subsequent calls
+  // to StartDequeue will return the same pointer.
+  void* StartDequeue();
+  void FinishDequeue();
+  // Due to a presence of slipping between the producer and the consumer,
+  // the queue must be notified whether producing has been finished in order
+  // to process remaining records from the buffer.
+  void FlushResidualRecords();
+  void TearDownConsumer();
+
+  typedef AtomicWord Cell;
+  // Reserved values for the first cell of a record.
+  static const Cell kClear = 0;  // Marks clean (processed) chunks.
+  static const Cell kEnd = -1;   // Marks the end of the buffer.
+
+ private:
+  struct ConsumerPosition {
+    Cell* dequeue_chunk_pos;
+    Cell* dequeue_chunk_poll_pos;
+    Cell* dequeue_pos;
+    Cell* dequeue_end_pos;
+  };
+
+  INLINE(void WrapPositionIfNeeded(Cell** pos));
+
+  const int record_size_;
+  const int chunk_size_in_bytes_;
+  const int chunk_size_;
+  const int buffer_size_;
+  const int producer_consumer_distance_;
+  Cell* buffer_;
+  // Store producer and consumer data in TLS to avoid modifying the
+  // same CPU cache line from two threads simultaneously.
+  Thread::LocalStorageKey consumer_key_;
+  Thread::LocalStorageKey producer_key_;
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_CIRCULAR_QUEUE_H_
index bc2e9d6..8f68766 100644 (file)
@@ -114,6 +114,10 @@ int random();
 namespace v8 {
 namespace internal {
 
+// Use AtomicWord for a machine-sized pointer. It is assumed that
+// reads and writes of naturally aligned values of this type are atomic.
+typedef intptr_t AtomicWord;
+
 class Semaphore;
 
 double ceiling(double x);
index f4964ae..28ead19 100644 (file)
@@ -39,6 +39,7 @@ SOURCES = {
     'test-alloc.cc',
     'test-api.cc',
     'test-ast.cc',
+    'test-circular-queue.cc',
     'test-compiler.cc',
     'test-conversions.cc',
     'test-dataflow.cc',
diff --git a/test/cctest/test-circular-queue.cc b/test/cctest/test-circular-queue.cc
new file mode 100644 (file)
index 0000000..aa981b8
--- /dev/null
@@ -0,0 +1,127 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+//
+// Tests of circular queues.
+
+#include "v8.h"
+#include "circular-queue-inl.h"
+#include "cctest.h"
+
+namespace i = v8::internal;
+
+using i::CircularQueue;
+using i::SamplingCircularQueue;
+
+
+TEST(SingleRecordCircularQueue) {
+  typedef int Record;
+  CircularQueue<Record> cq(sizeof(Record) * 2);
+  CHECK(cq.IsEmpty());
+  cq.Enqueue(1);
+  CHECK(!cq.IsEmpty());
+  Record rec = 0;
+  cq.Dequeue(&rec);
+  CHECK_EQ(1, rec);
+  CHECK(cq.IsEmpty());
+}
+
+
+TEST(MultipleRecordsCircularQueue) {
+  typedef int Record;
+  const int kQueueSize = 10;
+  CircularQueue<Record> cq(sizeof(Record) * (kQueueSize + 1));
+  CHECK(cq.IsEmpty());
+  cq.Enqueue(1);
+  CHECK(!cq.IsEmpty());
+  for (int i = 2; i <= 5; ++i) {
+    cq.Enqueue(i);
+    CHECK(!cq.IsEmpty());
+  }
+  Record rec = 0;
+  for (int i = 1; i <= 4; ++i) {
+    CHECK(!cq.IsEmpty());
+    cq.Dequeue(&rec);
+    CHECK_EQ(i, rec);
+  }
+  for (int i = 6; i <= 12; ++i) {
+    cq.Enqueue(i);
+    CHECK(!cq.IsEmpty());
+  }
+  for (int i = 5; i <= 12; ++i) {
+    CHECK(!cq.IsEmpty());
+    cq.Dequeue(&rec);
+    CHECK_EQ(i, rec);
+  }
+  CHECK(cq.IsEmpty());
+}
+
+
+TEST(SamplingCircularQueue) {
+  typedef int Record;
+  const int kRecordsPerChunk = 4;
+  SamplingCircularQueue scq(sizeof(Record),
+                            kRecordsPerChunk * sizeof(Record),
+                            3);
+  scq.SetUpProducer();
+  scq.SetUpConsumer();
+
+  // Check that we are using non-reserved values.
+  CHECK_NE(SamplingCircularQueue::kClear, 1);
+  CHECK_NE(SamplingCircularQueue::kEnd, 1);
+  // Fill up the first chunk.
+  CHECK_EQ(NULL, scq.StartDequeue());
+  for (int i = 1; i < 1 + kRecordsPerChunk; ++i) {
+    Record* rec = reinterpret_cast<Record*>(scq.Enqueue());
+    CHECK_NE(NULL, rec);
+    *rec = i;
+    CHECK_EQ(NULL, scq.StartDequeue());
+  }
+
+  // Fill up the second chunk. Consumption must still be unavailable.
+  CHECK_EQ(NULL, scq.StartDequeue());
+  for (int i = 10; i < 10 + kRecordsPerChunk; ++i) {
+    Record* rec = reinterpret_cast<Record*>(scq.Enqueue());
+    CHECK_NE(NULL, rec);
+    *rec = i;
+    CHECK_EQ(NULL, scq.StartDequeue());
+  }
+
+  Record* rec = reinterpret_cast<Record*>(scq.Enqueue());
+  CHECK_NE(NULL, rec);
+  *rec = 20;
+  // Now as we started filling up the third chunk, consumption
+  // must become possible.
+  CHECK_NE(NULL, scq.StartDequeue());
+
+  // Consume the first chunk.
+  for (int i = 1; i < 1 + kRecordsPerChunk; ++i) {
+    Record* rec = reinterpret_cast<Record*>(scq.StartDequeue());
+    CHECK_NE(NULL, rec);
+    CHECK_EQ(i, *rec);
+    CHECK_EQ(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
+    scq.FinishDequeue();
+    CHECK_NE(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
+  }
+  // Now consumption must not be possible, as consumer now polls
+  // the first chunk for emptinness.
+  CHECK_EQ(NULL, scq.StartDequeue());
+
+  scq.FlushResidualRecords();
+  // From now, consumer no more polls ahead of the current chunk,
+  // so it's possible to consume the second chunk.
+  CHECK_NE(NULL, scq.StartDequeue());
+  // Consume the second chunk
+  for (int i = 10; i < 10 + kRecordsPerChunk; ++i) {
+    Record* rec = reinterpret_cast<Record*>(scq.StartDequeue());
+    CHECK_NE(NULL, rec);
+    CHECK_EQ(i, *rec);
+    CHECK_EQ(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
+    scq.FinishDequeue();
+    CHECK_NE(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
+  }
+  // Consumption must still be possible as the first cell of the
+  // last chunk is not clean.
+  CHECK_NE(NULL, scq.StartDequeue());
+
+  scq.TearDownConsumer();
+  scq.TearDownProducer();
+}
index d859fb0..a0cc3e3 100644 (file)
         '../../src/char-predicates.h',
         '../../src/checks.cc',
         '../../src/checks.h',
+        '../../src/circular-queue.cc',
         '../../src/code-stubs.cc',
         '../../src/code-stubs.h',
         '../../src/code.h',
index ccb197a..9ef2665 100644 (file)
                89FB0E3A0F8E533F00B04B3C /* d8-posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89FB0E360F8E531900B04B3C /* d8-posix.cc */; };
                9F11D9A0105AF0A300EBE5B2 /* heap-profiler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F11D99E105AF0A300EBE5B2 /* heap-profiler.cc */; };
                9F11D9A1105AF0A300EBE5B2 /* heap-profiler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F11D99E105AF0A300EBE5B2 /* heap-profiler.cc */; };
+               9F2B3711114FF62D007CDAF4 /* circular-queue.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F2B370F114FF62D007CDAF4 /* circular-queue.cc */; };
+               9F2B3712114FF62D007CDAF4 /* circular-queue.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F2B370F114FF62D007CDAF4 /* circular-queue.cc */; };
                9F4B7B890FCC877A00DC4117 /* log-utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F4B7B870FCC877A00DC4117 /* log-utils.cc */; };
                9F4B7B8A0FCC877A00DC4117 /* log-utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F4B7B870FCC877A00DC4117 /* log-utils.cc */; };
                9F73E3B1114E61A100F84A5A /* profile-generator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F73E3AF114E61A100F84A5A /* profile-generator.cc */; };
                89FB0E370F8E531900B04B3C /* d8-windows.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "d8-windows.cc"; path = "../src/d8-windows.cc"; sourceTree = "<group>"; };
                9F11D99E105AF0A300EBE5B2 /* heap-profiler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "heap-profiler.cc"; sourceTree = "<group>"; };
                9F11D99F105AF0A300EBE5B2 /* heap-profiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "heap-profiler.h"; sourceTree = "<group>"; };
+               9F2B370E114FF62D007CDAF4 /* circular-queue-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "circular-queue-inl.h"; sourceTree = "<group>"; };
+               9F2B370F114FF62D007CDAF4 /* circular-queue.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "circular-queue.cc"; sourceTree = "<group>"; };
+               9F2B3710114FF62D007CDAF4 /* circular-queue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "circular-queue.h"; sourceTree = "<group>"; };
                9F4B7B870FCC877A00DC4117 /* log-utils.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "log-utils.cc"; sourceTree = "<group>"; };
                9F4B7B880FCC877A00DC4117 /* log-utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "log-utils.h"; sourceTree = "<group>"; };
                9F73E3AE114E61A100F84A5A /* profile-generator-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "profile-generator-inl.h"; sourceTree = "<group>"; };
                                897FF10E0E719B8F00D62E90 /* char-predicates.h */,
                                897FF10F0E719B8F00D62E90 /* checks.cc */,
                                897FF1100E719B8F00D62E90 /* checks.h */,
+                               9F2B370E114FF62D007CDAF4 /* circular-queue-inl.h */,
+                               9F2B370F114FF62D007CDAF4 /* circular-queue.cc */,
+                               9F2B3710114FF62D007CDAF4 /* circular-queue.h */,
                                897FF1110E719B8F00D62E90 /* code-stubs.cc */,
                                897FF1120E719B8F00D62E90 /* code-stubs.h */,
                                897FF1130E719B8F00D62E90 /* code.h */,
                                9FBE03DE10BD409900F8BFBA /* fast-codegen.cc in Sources */,
                                9FBE03E210BD40EA00F8BFBA /* fast-codegen-ia32.cc in Sources */,
                                9F73E3B2114E61A100F84A5A /* profile-generator.cc in Sources */,
+                               9F2B3712114FF62D007CDAF4 /* circular-queue.cc in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                9FBE03DF10BD409900F8BFBA /* fast-codegen.cc in Sources */,
                                9FBE03E510BD412600F8BFBA /* fast-codegen-arm.cc in Sources */,
                                9F73E3B1114E61A100F84A5A /* profile-generator.cc in Sources */,
+                               9F2B3711114FF62D007CDAF4 /* circular-queue.cc in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 37ea01c..be32bcf 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\circular-queue-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\circular-queue.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\circular-queue.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\code-stubs.cc"
                                >
                        </File>
index de2d65a..74a7359 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\circular-queue-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\circular-queue.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\circular-queue.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\code-stubs.cc"
                                >
                        </File>
index 29f4ed7..f573910 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\circular-queue-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\circular-queue.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\circular-queue.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\code-stubs.cc"
                                >
                        </File>
index 9acb835..7d0c4ff 100644 (file)
                        >
                </File>
                <File
+                       RelativePath="..\..\test\cctest\test-circular-queue.cc"
+                       >
+               </File>
+               <File
                        RelativePath="..\..\test\cctest\test-compiler.cc"
                        >
                </File>
                        >
                </File>
                <File
+                       RelativePath="..\..\test\cctest\test-profile-generator.cc"
+                       >
+               </File>
+               <File
                        RelativePath="..\..\test\cctest\test-serialize.cc"
                        >
                </File>
index 7ff953e..ee08b4f 100644 (file)
                        >
                </File>
                <File
+                       RelativePath="..\..\test\cctest\test-circular-queue.cc"
+                       >
+               </File>
+               <File
                        RelativePath="..\..\test\cctest\test-compiler.cc"
                        >
                </File>
                        >
                </File>
                <File
+                       RelativePath="..\..\test\cctest\test-profile-generator.cc"
+                       >
+               </File>
+               <File
                        RelativePath="..\..\test\cctest\test-serialize.cc"
                        >
                </File>
index 1e9044b..ee80c41 100644 (file)
                        >
                </File>
                <File
+                       RelativePath="..\..\test\cctest\test-circular-queue.cc"
+                       >
+               </File>
+               <File
                        RelativePath="..\..\test\cctest\test-compiler.cc"
                        >
                </File>
                        >
                </File>
                <File
+                       RelativePath="..\..\test\cctest\test-profile-generator.cc"
+                       >
+               </File>
+               <File
                        RelativePath="..\..\test\cctest\test-serialize.cc"
                        >
                </File>