Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | |
| 2 // Redistribution and use in source and binary forms, with or without | |
| 3 // modification, are permitted provided that the following conditions are | |
| 4 // met: | |
| 5 // | |
| 6 // * Redistributions of source code must retain the above copyright | |
| 7 // notice, this list of conditions and the following disclaimer. | |
| 8 // * Redistributions in binary form must reproduce the above | |
| 9 // copyright notice, this list of conditions and the following | |
| 10 // disclaimer in the documentation and/or other materials provided | |
| 11 // with the distribution. | |
| 12 // * Neither the name of Google Inc. nor the names of its | |
| 13 // contributors may be used to endorse or promote products derived | |
| 14 // from this software without specific prior written permission. | |
| 15 // | |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 27 | |
| 28 #include "crankshaft-thread.h" | |
| 29 | |
| 30 #include <set> | |
| 31 | |
| 32 #include "debug.h" | |
| 33 #include "flags.h" | |
| 34 #include "lithium.h" | |
| 35 #include "v8threads.h" | |
| 36 | |
| 37 namespace v8 { | |
| 38 namespace internal { | |
| 39 | |
| 40 | |
| 41 static void FreeDeletedIsolates(std::set<Isolate*> *deleted_isolates) { | |
| 42 for (std::set<Isolate*>::iterator i = deleted_isolates->begin(), | |
|
danno
2012/05/22 10:32:19
We don't use STL in V8, you'll have to find anothe
| |
| 43 e = deleted_isolates->end(); | |
| 44 i != e; ++i) | |
| 45 // We simply call free on the Isolates since the destructor for | |
| 46 // each of these instances has already been called. | |
| 47 free(*i); | |
| 48 } | |
| 49 | |
| 50 void CrankshaftThread::WorkerThread::Run() { | |
| 51 std::set<i::Isolate *> deleted_isolates; | |
| 52 // The loop lock is given up at two sites. For this reason, | |
| 53 // successfully acquiring the lock from another thread guarantees | |
| 54 // that this thread is one of those two places. | |
| 55 loop_lock_->Lock(); | |
| 56 | |
| 57 while (true) { | |
| 58 // Whenever loop_lock_ is unlocked isolate_ is set to the Isolate | |
| 59 // currently being processed. | |
| 60 Acquire_Store(&isolate_, static_cast<AtomicWord>(0)); | |
| 61 | |
| 62 loop_lock_->Unlock(); | |
|
danno
2012/05/22 10:32:19
I don't think you need the loop lock at all. Just
sanjoy
2012/05/22 11:38:55
I needed a place in the code where I'm assured iso
| |
| 63 queue_semaphore_->Wait(); | |
| 64 loop_lock_->Lock(); | |
| 65 | |
| 66 if (Release_Load(&stop_loop_)) { | |
| 67 FreeDeletedIsolates(&deleted_isolates); | |
| 68 // We need to unlock the loop lock since it is possible the | |
| 69 // thread stopping the worker thread set stop_loop_ after we | |
| 70 // locked loop_lock_ and is currently waiting on loop_lock_. | |
| 71 loop_lock_->Unlock(); | |
| 72 return; | |
| 73 } | |
| 74 | |
| 75 WorkElement w_element; | |
| 76 work_queue_.Dequeue(&w_element); | |
| 77 | |
| 78 if (!w_element.dummy) { | |
| 79 i::Isolate* isolate = w_element.isolate; | |
| 80 if (deleted_isolates.find(isolate) != deleted_isolates.end()) | |
| 81 continue; | |
| 82 | |
| 83 Acquire_Store(&isolate_, reinterpret_cast<AtomicWord>(isolate)); | |
|
danno
2012/05/22 10:32:19
I think you can get rid of both isolate_ and loop_
| |
| 84 loop_lock_->Unlock(); | |
| 85 | |
| 86 { | |
| 87 // Can't use the Locker object here since we can't unlock if | |
| 88 // this isolate has been marked for deletion. | |
| 89 isolate->thread_manager()->Lock(); | |
| 90 loop_lock_->Lock(); | |
| 91 | |
| 92 bool to_stop = Release_Load(&stop_loop_); | |
| 93 | |
| 94 if (isolate->to_delete()) { | |
| 95 // We don't delete the Isolate lest the same memory gets | |
| 96 // allocated to another Isolate and the crankshaft thread | |
| 97 // gets confused. We still invoke the destructor to free | |
| 98 // the Isolate's members. | |
| 99 isolate->~Isolate(); | |
|
danno
2012/05/22 10:32:19
What happens if two functions from the isolate are
| |
| 100 deleted_isolates.insert(isolate); | |
| 101 if (to_stop) | |
| 102 return; | |
| 103 else | |
| 104 continue; | |
| 105 } | |
| 106 | |
| 107 if (to_stop) { | |
| 108 FreeDeletedIsolates(&deleted_isolates); | |
|
danno
2012/05/22 10:32:19
How big are the isolates? Can we really afford to
| |
| 109 loop_lock_->Unlock(); | |
| 110 return; | |
| 111 } | |
| 112 | |
| 113 bool top_level = true; | |
| 114 if (isolate->thread_manager()->RestoreThread()) { | |
| 115 top_level = false; | |
| 116 } else { | |
| 117 i::ExecutionAccess access(isolate); | |
| 118 isolate->stack_guard()->ClearThread(access); | |
| 119 isolate->stack_guard()->InitThread(access); | |
| 120 } | |
|
danno
2012/05/22 10:32:19
Don't you have to do this after the Enter to ensur
sanjoy
2012/05/22 11:38:55
I don't think so, I've already acquired the isolat
| |
| 121 | |
| 122 isolate->Enter(); | |
| 123 { | |
| 124 HandleScope scope(isolate); | |
| 125 if (!w_element.function->IsOptimized()) { | |
| 126 i::Handle<i::Context> ctx(w_element.function->context()); | |
| 127 isolate->handle_scope_implementer()->EnterContext(ctx); | |
| 128 isolate->handle_scope_implementer()->SaveContext( | |
| 129 isolate->context()); | |
| 130 isolate->set_context(*ctx); | |
| 131 | |
| 132 while (CompileJSFunction(isolate, | |
|
danno
2012/05/22 10:32:19
This won't work. You will have to create a handle
| |
| 133 w_element.function)->IsFailure()) { | |
| 134 } | |
| 135 | |
| 136 isolate->handle_scope_implementer()->LeaveLastContext(); | |
| 137 i::Context* last_context = | |
| 138 isolate->handle_scope_implementer()->RestoreContext(); | |
| 139 isolate->set_context(last_context); | |
| 140 isolate->set_context_exit_happened(true); | |
| 141 #ifdef DEBUG | |
| 142 functions_compiled_++; | |
| 143 #endif | |
| 144 } | |
| 145 } | |
| 146 isolate->global_handles()->Destroy( | |
| 147 reinterpret_cast<Object **>(w_element.function.location())); | |
| 148 isolate->Exit(); | |
| 149 | |
| 150 if (top_level) | |
| 151 isolate->thread_manager()->ArchiveThread(); | |
| 152 else | |
| 153 isolate->thread_manager()->FreeThreadResources(); | |
| 154 | |
| 155 isolate->thread_manager()->Unlock(); | |
| 156 } | |
| 157 } | |
| 158 } | |
| 159 } | |
| 160 | |
| 161 | |
| 162 void CrankshaftThread::WorkerThread::AddElement(const WorkElement &we) { | |
| 163 { | |
| 164 // We need the queue_lock_ since UnboundQueue is single producer / | |
| 165 // single consumer, while we have a multiple producer / single | |
| 166 // consumer situation here. | |
| 167 ScopedLock lock(queue_lock_); | |
| 168 work_queue_.Enqueue(we); | |
| 169 } | |
| 170 queue_semaphore_->Signal(); | |
| 171 } | |
| 172 | |
| 173 | |
| 174 void CrankshaftThread::WorkerThread::StopThread() { | |
| 175 ASSERT(!stop_loop_); | |
| 176 Acquire_Store(&stop_loop_, static_cast<AtomicWord>(true)); | |
| 177 | |
| 178 { | |
| 179 ScopedLock lock(loop_lock_); | |
| 180 // Once we have the loop_lock_, we're assured that the worker | |
| 181 // thread is in one of the two sites where it gives it up. | |
| 182 i::Isolate *isolate = | |
| 183 reinterpret_cast<i::Isolate *>(NoBarrier_Load(&isolate_)); | |
| 184 | |
| 185 if (!isolate) { | |
| 186 // If isolate is NULL, we the worker thread it is possible the | |
| 187 // worker thread waiting on queue_semaphore_. Insert a dummy | |
| 188 // element to get it past the semaphore. | |
| 189 WorkElement element; | |
| 190 element.dummy = true; | |
| 191 AddElement(element); | |
|
danno
2012/05/22 10:32:19
Why do you need the explicit dummy element? You se
sanjoy
2012/05/22 11:38:55
Right, it is not needed. I'll remove it in the ne
| |
| 192 } else if (isolate->thread_manager() && | |
| 193 isolate->thread_manager()->IsLockedByCurrentThread()) { | |
| 194 isolate->thread_manager()->ArchiveThread(); | |
| 195 isolate->thread_manager()->Unlock(); | |
| 196 } else { | |
| 197 ASSERT(!isolate->thread_manager()->IsLockedByCurrentThread() || | |
| 198 isolate->to_delete()); | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 Join(); | |
| 203 | |
| 204 ElementsAccessor::TearDown(); | |
|
danno
2012/05/22 10:32:19
Why are these here? Shouldn't they be in V8 teardo
| |
| 205 LOperand::TearDownCaches(); | |
| 206 RegisteredExtension::UnregisterAll(); | |
| 207 | |
| 208 #ifdef DEBUG | |
| 209 PrintF(stderr, " > %d functions compiled concurrently!\n", | |
| 210 functions_compiled_); | |
|
danno
2012/05/22 10:32:19
use v8-counters for this
| |
| 211 #endif | |
| 212 } | |
| 213 | |
| 214 | |
| 215 void CrankshaftThread::StartThread() { | |
| 216 ASSERT(FLAG_concurrent_crankshaft); | |
| 217 ASSERT(!worker_instance_); | |
| 218 | |
| 219 #ifdef DEBUG | |
| 220 PrintF(stderr, " > Starting Crankshaft Thread\n"); | |
|
danno
2012/05/22 10:32:19
Remove the print, please
| |
| 221 #endif | |
|
danno
2012/05/22 10:32:19
Remove the print, please
| |
| 222 | |
| 223 Thread::Options o("CShaftThread"); | |
| 224 worker_instance_ = new WorkerThread(o); | |
| 225 worker_instance_->Start(); | |
| 226 } | |
| 227 | |
| 228 | |
| 229 void CrankshaftThread::StopThread() { | |
| 230 ASSERT(FLAG_concurrent_crankshaft); | |
| 231 ASSERT(worker_instance_); | |
| 232 | |
| 233 worker_instance_->StopThread(); | |
| 234 } | |
| 235 | |
| 236 | |
| 237 void CrankshaftThread::AddJob(Isolate *isolate, | |
| 238 i::Handle<JSFunction> function) { | |
| 239 ASSERT(FLAG_concurrent_crankshaft); | |
| 240 ASSERT(worker_instance_); | |
| 241 ASSERT(isolate->thread_manager()->IsLockedByCurrentThread()); | |
| 242 | |
| 243 WorkElement we; | |
| 244 we.function = function; | |
| 245 we.isolate = isolate; | |
| 246 | |
| 247 worker_instance_->AddElement(we); | |
| 248 | |
| 249 if (!isolate->debugger()->IsDebuggerActive()) { | |
| 250 Unlocker unlock(reinterpret_cast<v8::Isolate *>(isolate)); | |
| 251 Thread::YieldCPU(); | |
| 252 } | |
| 253 } | |
| 254 | |
| 255 | |
| 256 CrankshaftThread::WorkerThread *CrankshaftThread::worker_instance_ = NULL; | |
| 257 | |
| 258 } } // namespace v8::internal | |
| 259 | |
| OLD | NEW |