Chromium Code Reviews| Index: src/contexts.cc |
| diff --git a/src/contexts.cc b/src/contexts.cc |
| index 012944e2c28b5344240852166b40ec2a6cd48cf4..1d56b430eef1f7a6377bbae3a9c692ad4d3f0e37 100644 |
| --- a/src/contexts.cc |
| +++ b/src/contexts.cc |
| @@ -408,6 +408,191 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags, |
| return Handle<Object>::null(); |
| } |
| +static const int kSharedOffset = 0; |
| +static const int kCachedCodeOffset = 1; |
| +static const int kLiteralsOffset = 2; |
| +static const int kOsrAstIdOffset = 3; |
| +static const int kEntryLength = 4; |
| +static const int kInitialLength = kEntryLength; |
| + |
| +int Context::SearchOptimizedCodeMapEntry(SharedFunctionInfo* shared, |
| + BailoutId osr_ast_id) { |
| + DisallowHeapAllocation no_gc; |
| + DCHECK(this->IsNativeContext()); |
| + if (!OptimizedCodeMapIsCleared()) { |
| + FixedArray* optimized_code_map = this->osrd_function_table(); |
| + int length = optimized_code_map->length(); |
| + Smi* osr_ast_id_smi = Smi::FromInt(osr_ast_id.ToInt()); |
| + for (int i = 0; i < length; i += kEntryLength) { |
| + if (WeakCell::cast(optimized_code_map->get(i + kSharedOffset))->value() == |
| + shared && |
| + optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) { |
| + return i; |
| + } |
| + } |
| + } |
| + return -1; |
| +} |
| + |
| +void Context::SearchOptimizedCodeMap(SharedFunctionInfo* shared, |
| + BailoutId osr_ast_id, Code** pcode, |
| + LiteralsArray** pliterals) { |
| + DCHECK(this->IsNativeContext()); |
| + int entry = SearchOptimizedCodeMapEntry(shared, osr_ast_id); |
| + if (entry != -1) { |
| + FixedArray* code_map = osrd_function_table(); |
| + DCHECK_LE(entry + kEntryLength, code_map->length()); |
| + WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset)); |
| + WeakCell* literals_cell = |
| + WeakCell::cast(code_map->get(entry + kLiteralsOffset)); |
| + |
| + *pcode = cell->cleared() ? nullptr : Code::cast(cell->value()); |
| + *pliterals = literals_cell->cleared() |
| + ? nullptr |
| + : LiteralsArray::cast(literals_cell->value()); |
| + } else { |
| + *pcode = nullptr; |
| + *pliterals = nullptr; |
| + } |
| +} |
| + |
| +void Context::AddToOptimizedCodeMap(Handle<Context> native_context, |
| + Handle<SharedFunctionInfo> shared, |
| + Handle<Code> code, |
| + Handle<LiteralsArray> literals, |
| + BailoutId osr_ast_id) { |
| + DCHECK(native_context->IsNativeContext()); |
| + Isolate* isolate = native_context->GetIsolate(); |
| + if (isolate->serializer_enabled()) return; |
| + |
| + STATIC_ASSERT(kEntryLength == 4); |
| + Handle<FixedArray> new_code_map; |
| + int entry; |
| + |
| + if (native_context->OptimizedCodeMapIsCleared()) { |
| + new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED); |
| + entry = 0; |
| + } else { |
| + Handle<FixedArray> old_code_map(native_context->osrd_function_table(), |
| + isolate); |
| + entry = native_context->SearchOptimizedCodeMapEntry(*shared, osr_ast_id); |
| + if (entry >= 0) { |
| + // Just set the code and literals of the entry. |
| + Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code); |
|
ulan
2016/12/07 14:54:57
Since the code is optimized, Code::WeakCellFor(cod
|
| + old_code_map->set(entry + kCachedCodeOffset, *code_cell); |
| + Handle<WeakCell> literals_cell = |
| + isolate->factory()->NewWeakCell(literals); |
| + old_code_map->set(entry + kLiteralsOffset, *literals_cell); |
| + return; |
| + } |
| + |
| + // Can we reuse an entry? |
| + DCHECK(entry < 0); |
| + int length = old_code_map->length(); |
| + for (int i = 0; i < length; i += kEntryLength) { |
| + if (WeakCell::cast(old_code_map->get(i + kSharedOffset))->cleared()) { |
| + new_code_map = old_code_map; |
| + entry = i; |
| + break; |
| + } |
| + } |
| + |
| + if (entry < 0) { |
| + // Copy old optimized code map and append one new entry. |
| + new_code_map = isolate->factory()->CopyFixedArrayAndGrow( |
| + old_code_map, kEntryLength, TENURED); |
| + // TODO(mstarzinger): Temporary workaround. The allocation above might |
|
Michael Starzinger
2016/12/07 09:26:31
This should no longer happen now that flushing has
mvstanton
2016/12/07 14:42:32
Done.
|
| + // have flushed the optimized code map and the copy we created is full of |
| + // holes. For now we just give up on adding the entry and pretend it got |
| + // flushed. |
| + if (native_context->OptimizedCodeMapIsCleared()) return; |
| + entry = old_code_map->length(); |
| + } |
| + } |
| + |
| + // TODO(mvstanton): isn't there a cached weak cell in the Code class? |
| + Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code); |
|
ulan
2016/12/07 14:54:57
Code::WeakCellFor(code)
|
| + Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals); |
| + // TODO(mvstanton): Should we cache a weak cell for a SharedFunctionInfo? |
| + Handle<WeakCell> shared_cell = isolate->factory()->NewWeakCell(shared); |
| + |
| + new_code_map->set(entry + kSharedOffset, *shared_cell); |
| + new_code_map->set(entry + kCachedCodeOffset, *code_cell); |
| + new_code_map->set(entry + kLiteralsOffset, *literals_cell); |
| + new_code_map->set(entry + kOsrAstIdOffset, Smi::FromInt(osr_ast_id.ToInt())); |
| + |
| +#ifdef DEBUG |
| + for (int i = 0; i < new_code_map->length(); i += kEntryLength) { |
| + WeakCell* cell = WeakCell::cast(new_code_map->get(i + kSharedOffset)); |
| + DCHECK(cell->cleared() || cell->value()->IsSharedFunctionInfo()); |
| + cell = WeakCell::cast(new_code_map->get(i + kCachedCodeOffset)); |
| + DCHECK(cell->cleared() || |
| + (cell->value()->IsCode() && |
| + Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION)); |
| + cell = WeakCell::cast(new_code_map->get(i + kLiteralsOffset)); |
| + DCHECK(cell->cleared() || cell->value()->IsFixedArray()); |
| + DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi()); |
| + } |
| +#endif |
| + |
| + FixedArray* old_code_map = native_context->osrd_function_table(); |
| + if (old_code_map != *new_code_map) { |
| + native_context->set_osrd_function_table(*new_code_map); |
| + } |
| +} |
| + |
| +void Context::EvictFromOptimizedCodeMap(Code* optimized_code, |
| + const char* reason) { |
| + DCHECK(IsNativeContext()); |
| + DisallowHeapAllocation no_gc; |
| + if (OptimizedCodeMapIsCleared()) return; |
| + |
| + Heap* heap = GetHeap(); |
| + FixedArray* code_map = osrd_function_table(); |
| + int dst = 0; |
| + int length = code_map->length(); |
| + for (int src = 0; src < length; src += kEntryLength) { |
| + if (WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() == |
| + optimized_code) { |
| + BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value()); |
| + if (FLAG_trace_opt) { |
| + PrintF( |
| + "[evicting entry from native context optimizing code map (%s) for ", |
| + reason); |
| + ShortPrint(); |
| + DCHECK(!osr.IsNone()); |
| + PrintF(" (osr ast id %d)]\n", osr.ToInt()); |
| + } |
| + // Evict the src entry by not copying it to the dst entry. |
| + continue; |
| + } |
| + // Keep the src entry by copying it to the dst entry. |
| + if (dst != src) { |
| + code_map->set(dst + kSharedOffset, code_map->get(src + kSharedOffset)); |
| + code_map->set(dst + kCachedCodeOffset, |
| + code_map->get(src + kCachedCodeOffset)); |
| + code_map->set(dst + kLiteralsOffset, |
| + code_map->get(src + kLiteralsOffset)); |
| + code_map->set(dst + kOsrAstIdOffset, |
| + code_map->get(src + kOsrAstIdOffset)); |
| + } |
| + dst += kEntryLength; |
| + } |
| + if (dst != length) { |
| + // Always trim even when array is cleared because of heap verifier. |
| + heap->RightTrimFixedArray(code_map, length - dst); |
| + if (code_map->length() == 0) { |
| + ClearOptimizedCodeMap(); |
| + } |
| + } |
| +} |
| + |
| +void Context::ClearOptimizedCodeMap() { |
| + DCHECK(IsNativeContext()); |
| + FixedArray* empty_fixed_array = GetHeap()->empty_fixed_array(); |
| + // TODO(mvstanton): we could skip the write barrier... |
| + set_osrd_function_table(empty_fixed_array); |
| +} |
| void Context::AddOptimizedFunction(JSFunction* function) { |
| DCHECK(IsNativeContext()); |