Remove JSFunctionResultCache.

There is only one use case for it: String.prototype.search converts a
string argument into a RegExp. The cache is used to avoid repeating that
conversion. However, this does not make the added complexity worthwhile.

Review URL: https://codereview.chromium.org/1267493006

Cr-Commit-Position: refs/heads/master@{#29985}
This commit is contained in:
yangguo 2015-08-03 11:13:56 -07:00 committed by Commit bot
parent 8d2eec506f
commit 4a2e4420b8
27 changed files with 10 additions and 924 deletions

View File

@ -6913,7 +6913,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 = 87;
static const int kContextEmbedderDataIndex = 86;
static const int kFullStringRepresentationMask = 0x07;
static const int kStringEncodingMask = 0x4;
static const int kExternalTwoByteRepresentationTag = 0x02;

View File

@ -101,8 +101,6 @@ namespace internal {
V(kIndexIsTooLarge, "Index is too large") \
V(kInlinedRuntimeFunctionFastOneByteArrayJoin, \
"Inlined runtime function: FastOneByteArrayJoin") \
V(kInlinedRuntimeFunctionGetFromCache, \
"Inlined runtime function: GetFromCache") \
V(kInliningBailedOut, "Inlining bailed out") \
V(kInputGPRIsExpectedToHaveUpper32Cleared, \
"Input GPR is expected to have upper32 cleared") \

View File

@ -241,7 +241,6 @@ class Genesis BASE_EMBEDDED {
bool InstallExtraNatives();
void InstallBuiltinFunctionIds();
void InstallExperimentalBuiltinFunctionIds();
void InstallJSFunctionResultCaches();
void InitializeNormalizedMapCaches();
enum ExtensionTraversalState {
@ -2698,50 +2697,6 @@ void Genesis::InstallExperimentalBuiltinFunctionIds() {
#undef INSTALL_BUILTIN_ID
// Do not forget to update macros.py with named constant
// of cache id.
#define JSFUNCTION_RESULT_CACHE_LIST(F) \
F(16, native_context()->regexp_function())
static FixedArray* CreateCache(int size, Handle<JSFunction> factory_function) {
Factory* factory = factory_function->GetIsolate()->factory();
// Caches are supposed to live for a long time, allocate in old space.
int array_size = JSFunctionResultCache::kEntriesIndex + 2 * size;
// Cannot use cast as object is not fully initialized yet.
JSFunctionResultCache* cache = reinterpret_cast<JSFunctionResultCache*>(
*factory->NewFixedArrayWithHoles(array_size, TENURED));
cache->set(JSFunctionResultCache::kFactoryIndex, *factory_function);
cache->MakeZeroSize();
return cache;
}
void Genesis::InstallJSFunctionResultCaches() {
const int kNumberOfCaches = 0 +
#define F(size, func) + 1
JSFUNCTION_RESULT_CACHE_LIST(F)
#undef F
;
Handle<FixedArray> caches =
factory()->NewFixedArray(kNumberOfCaches, TENURED);
int index = 0;
#define F(size, func) do { \
FixedArray* cache = CreateCache((size), Handle<JSFunction>(func)); \
caches->set(index++, cache); \
} while (false)
JSFUNCTION_RESULT_CACHE_LIST(F);
#undef F
native_context()->set_jsfunction_result_caches(*caches);
}
void Genesis::InitializeNormalizedMapCaches() {
Handle<NormalizedMapCache> cache = NormalizedMapCache::New(isolate());
native_context()->set_normalized_map_cache(*cache);
@ -3252,7 +3207,6 @@ Genesis::Genesis(Isolate* isolate,
CreateNewGlobals(global_proxy_template, global_proxy);
HookUpGlobalProxy(global_object, global_proxy);
InitializeGlobal(global_object, empty_function, context_type);
InstallJSFunctionResultCaches();
InitializeNormalizedMapCaches();
if (!InstallNatives(context_type)) return;

View File

@ -142,7 +142,6 @@ enum BindingFlags {
V(GET_STACK_TRACE_LINE_INDEX, JSFunction, get_stack_trace_line_fun) \
V(CONFIGURE_GLOBAL_INDEX, JSFunction, configure_global_fun) \
V(FUNCTION_CACHE_INDEX, ObjectHashTable, function_cache) \
V(JSFUNCTION_RESULT_CACHES_INDEX, FixedArray, jsfunction_result_caches) \
V(NORMALIZED_MAP_CACHE_INDEX, Object, normalized_map_cache) \
V(RUNTIME_CONTEXT_INDEX, Context, runtime_context) \
V(CALL_AS_FUNCTION_DELEGATE_INDEX, JSFunction, call_as_function_delegate) \
@ -406,7 +405,6 @@ class Context: public FixedArray {
GET_STACK_TRACE_LINE_INDEX,
CONFIGURE_GLOBAL_INDEX,
FUNCTION_CACHE_INDEX,
JSFUNCTION_RESULT_CACHES_INDEX,
NORMALIZED_MAP_CACHE_INDEX,
RUNTIME_CONTEXT_INDEX,
CALL_AS_FUNCTION_DELEGATE_INDEX,

View File

@ -4286,55 +4286,6 @@ void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
}
void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(2, args->length());
DCHECK_NOT_NULL(args->at(0)->AsLiteral());
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
Handle<FixedArray> jsfunction_result_caches(
isolate()->native_context()->jsfunction_result_caches());
if (jsfunction_result_caches->length() <= cache_id) {
__ Abort(kAttemptToUseUndefinedCache);
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
context()->Plug(r0);
return;
}
VisitForAccumulatorValue(args->at(1));
Register key = r0;
Register cache = r1;
__ ldr(cache, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
__ ldr(cache, FieldMemOperand(cache, GlobalObject::kNativeContextOffset));
__ ldr(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
__ ldr(cache,
FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
Label done, not_found;
__ ldr(r2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset));
// r2 now holds finger offset as a smi.
__ add(r3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
// r3 now points to the start of fixed array elements.
__ ldr(r2, MemOperand::PointerAddressFromSmiKey(r3, r2, PreIndex));
// Note side effect of PreIndex: r3 now points to the key of the pair.
__ cmp(key, r2);
__ b(ne, &not_found);
__ ldr(r0, MemOperand(r3, kPointerSize));
__ b(&done);
__ bind(&not_found);
// Call runtime to perform the lookup.
__ Push(cache, key);
__ CallRuntime(Runtime::kGetFromCacheRT, 2);
__ bind(&done);
context()->Plug(r0);
}
void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
VisitForAccumulatorValue(args->at(0));

View File

@ -3999,54 +3999,6 @@ void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
}
void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(2, args->length());
DCHECK_NOT_NULL(args->at(0)->AsLiteral());
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
Handle<FixedArray> jsfunction_result_caches(
isolate()->native_context()->jsfunction_result_caches());
if (jsfunction_result_caches->length() <= cache_id) {
__ Abort(kAttemptToUseUndefinedCache);
__ LoadRoot(x0, Heap::kUndefinedValueRootIndex);
context()->Plug(x0);
return;
}
VisitForAccumulatorValue(args->at(1));
Register key = x0;
Register cache = x1;
__ Ldr(cache, GlobalObjectMemOperand());
__ Ldr(cache, FieldMemOperand(cache, GlobalObject::kNativeContextOffset));
__ Ldr(cache, ContextMemOperand(cache,
Context::JSFUNCTION_RESULT_CACHES_INDEX));
__ Ldr(cache,
FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
Label done;
__ Ldrsw(x2, UntagSmiFieldMemOperand(cache,
JSFunctionResultCache::kFingerOffset));
__ Add(x3, cache, FixedArray::kHeaderSize - kHeapObjectTag);
__ Add(x3, x3, Operand(x2, LSL, kPointerSizeLog2));
// Load the key and data from the cache.
__ Ldp(x2, x3, MemOperand(x3));
__ Cmp(key, x2);
__ CmovX(x0, x3, eq);
__ B(eq, &done);
// Call runtime to perform the lookup.
__ Push(cache, key);
__ CallRuntime(Runtime::kGetFromCacheRT, 2);
__ Bind(&done);
context()->Plug(x0);
}
void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
VisitForAccumulatorValue(args->at(0));

View File

@ -530,7 +530,6 @@ class FullCodeGenerator: public AstVisitor {
F(StringCompare) \
F(RegExpExec) \
F(RegExpConstructResult) \
F(GetFromCache) \
F(NumberToString) \
F(ToObject) \
F(DebugIsActive)

View File

@ -4188,55 +4188,6 @@ void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
}
void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(2, args->length());
DCHECK_NOT_NULL(args->at(0)->AsLiteral());
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
Handle<FixedArray> jsfunction_result_caches(
isolate()->native_context()->jsfunction_result_caches());
if (jsfunction_result_caches->length() <= cache_id) {
__ Abort(kAttemptToUseUndefinedCache);
__ mov(eax, isolate()->factory()->undefined_value());
context()->Plug(eax);
return;
}
VisitForAccumulatorValue(args->at(1));
Register key = eax;
Register cache = ebx;
Register tmp = ecx;
__ mov(cache, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX));
__ mov(cache,
FieldOperand(cache, GlobalObject::kNativeContextOffset));
__ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
__ mov(cache,
FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
Label done, not_found;
STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
__ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
// tmp now holds finger offset as a smi.
__ cmp(key, FixedArrayElementOperand(cache, tmp));
__ j(not_equal, &not_found);
__ mov(eax, FixedArrayElementOperand(cache, tmp, 1));
__ jmp(&done);
__ bind(&not_found);
// Call runtime to perform the lookup.
__ push(cache);
__ push(key);
__ CallRuntime(Runtime::kGetFromCacheRT, 2);
__ bind(&done);
context()->Plug(eax);
}
void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);

View File

@ -4307,60 +4307,6 @@ void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
}
void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(2, args->length());
DCHECK_NOT_NULL(args->at(0)->AsLiteral());
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
Handle<FixedArray> jsfunction_result_caches(
isolate()->native_context()->jsfunction_result_caches());
if (jsfunction_result_caches->length() <= cache_id) {
__ Abort(kAttemptToUseUndefinedCache);
__ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
context()->Plug(v0);
return;
}
VisitForAccumulatorValue(args->at(1));
Register key = v0;
Register cache = a1;
__ lw(cache, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
__ lw(cache, FieldMemOperand(cache, GlobalObject::kNativeContextOffset));
__ lw(cache,
ContextOperand(
cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
__ lw(cache,
FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
Label done, not_found;
STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
__ lw(a2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset));
// a2 now holds finger offset as a smi.
__ Addu(a3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
// a3 now points to the start of fixed array elements.
__ sll(at, a2, kPointerSizeLog2 - kSmiTagSize);
__ addu(a3, a3, at);
// a3 now points to key of indexed element of cache.
__ lw(a2, MemOperand(a3));
__ Branch(&not_found, ne, key, Operand(a2));
__ lw(v0, MemOperand(a3, kPointerSize));
__ Branch(&done);
__ bind(&not_found);
// Call runtime to perform the lookup.
__ Push(cache, key);
__ CallRuntime(Runtime::kGetFromCacheRT, 2);
__ bind(&done);
context()->Plug(v0);
}
void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
VisitForAccumulatorValue(args->at(0));

View File

@ -4310,60 +4310,6 @@ void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
}
void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(2, args->length());
DCHECK_NOT_NULL(args->at(0)->AsLiteral());
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
Handle<FixedArray> jsfunction_result_caches(
isolate()->native_context()->jsfunction_result_caches());
if (jsfunction_result_caches->length() <= cache_id) {
__ Abort(kAttemptToUseUndefinedCache);
__ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
context()->Plug(v0);
return;
}
VisitForAccumulatorValue(args->at(1));
Register key = v0;
Register cache = a1;
__ ld(cache, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
__ ld(cache, FieldMemOperand(cache, GlobalObject::kNativeContextOffset));
__ ld(cache,
ContextOperand(
cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
__ ld(cache,
FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
Label done, not_found;
STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
__ ld(a2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset));
// a2 now holds finger offset as a smi.
__ Daddu(a3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
// a3 now points to the start of fixed array elements.
__ SmiScale(at, a2, kPointerSizeLog2);
__ daddu(a3, a3, at);
// a3 now points to key of indexed element of cache.
__ ld(a2, MemOperand(a3));
__ Branch(&not_found, ne, key, Operand(a2));
__ ld(v0, MemOperand(a3, kPointerSize));
__ Branch(&done);
__ bind(&not_found);
// Call runtime to perform the lookup.
__ Push(cache, key);
__ CallRuntime(Runtime::kGetFromCacheRT, 2);
__ bind(&done);
context()->Plug(v0);
}
void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
VisitForAccumulatorValue(args->at(0));

View File

@ -4286,56 +4286,6 @@ void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
}
void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(2, args->length());
DCHECK_NOT_NULL(args->at(0)->AsLiteral());
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
Handle<FixedArray> jsfunction_result_caches(
isolate()->native_context()->jsfunction_result_caches());
if (jsfunction_result_caches->length() <= cache_id) {
__ Abort(kAttemptToUseUndefinedCache);
__ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
context()->Plug(r3);
return;
}
VisitForAccumulatorValue(args->at(1));
Register key = r3;
Register cache = r4;
__ LoadP(cache, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
__ LoadP(cache, FieldMemOperand(cache, GlobalObject::kNativeContextOffset));
__ LoadP(cache,
ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
__ LoadP(cache,
FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id)), r0);
Label done, not_found;
__ LoadP(r5, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset));
// r5 now holds finger offset as a smi.
__ addi(r6, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
// r6 now points to the start of fixed array elements.
__ SmiToPtrArrayOffset(r5, r5);
__ LoadPUX(r5, MemOperand(r6, r5));
// r6 now points to the key of the pair.
__ cmp(key, r5);
__ bne(&not_found);
__ LoadP(r3, MemOperand(r6, kPointerSize));
__ b(&done);
__ bind(&not_found);
// Call runtime to perform the lookup.
__ Push(cache, key);
__ CallRuntime(Runtime::kGetFromCacheRT, 2);
__ bind(&done);
context()->Plug(r3);
}
void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
VisitForAccumulatorValue(args->at(0));

View File

@ -4178,63 +4178,6 @@ void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
}
void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(2, args->length());
DCHECK_NOT_NULL(args->at(0)->AsLiteral());
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
Handle<FixedArray> jsfunction_result_caches(
isolate()->native_context()->jsfunction_result_caches());
if (jsfunction_result_caches->length() <= cache_id) {
__ Abort(kAttemptToUseUndefinedCache);
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
context()->Plug(rax);
return;
}
VisitForAccumulatorValue(args->at(1));
Register key = rax;
Register cache = rbx;
Register tmp = rcx;
__ movp(cache, ContextOperand(rsi, Context::GLOBAL_OBJECT_INDEX));
__ movp(cache,
FieldOperand(cache, GlobalObject::kNativeContextOffset));
__ movp(cache,
ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
__ movp(cache,
FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
Label done, not_found;
STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
__ movp(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
// tmp now holds finger offset as a smi.
SmiIndex index =
__ SmiToIndex(kScratchRegister, tmp, kPointerSizeLog2);
__ cmpp(key, FieldOperand(cache,
index.reg,
index.scale,
FixedArray::kHeaderSize));
__ j(not_equal, &not_found, Label::kNear);
__ movp(rax, FieldOperand(cache,
index.reg,
index.scale,
FixedArray::kHeaderSize + kPointerSize));
__ jmp(&done, Label::kNear);
__ bind(&not_found);
// Call runtime to perform the lookup.
__ Push(cache);
__ Push(key);
__ CallRuntime(Runtime::kGetFromCacheRT, 2);
__ bind(&done);
context()->Plug(rax);
}
void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);

View File

@ -4179,55 +4179,6 @@ void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
}
void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(2, args->length());
DCHECK_NOT_NULL(args->at(0)->AsLiteral());
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
Handle<FixedArray> jsfunction_result_caches(
isolate()->native_context()->jsfunction_result_caches());
if (jsfunction_result_caches->length() <= cache_id) {
__ Abort(kAttemptToUseUndefinedCache);
__ mov(eax, isolate()->factory()->undefined_value());
context()->Plug(eax);
return;
}
VisitForAccumulatorValue(args->at(1));
Register key = eax;
Register cache = ebx;
Register tmp = ecx;
__ mov(cache, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX));
__ mov(cache,
FieldOperand(cache, GlobalObject::kNativeContextOffset));
__ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
__ mov(cache,
FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
Label done, not_found;
STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
__ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
// tmp now holds finger offset as a smi.
__ cmp(key, FixedArrayElementOperand(cache, tmp));
__ j(not_equal, &not_found);
__ mov(eax, FixedArrayElementOperand(cache, tmp, 1));
__ jmp(&done);
__ bind(&not_found);
// Call runtime to perform the lookup.
__ push(cache);
__ push(key);
__ CallRuntime(Runtime::kGetFromCacheRT, 2);
__ bind(&done);
context()->Plug(eax);
}
void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);

View File

@ -1263,8 +1263,6 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
EXTRACT_CONTEXT_FIELD(EXTENSION_INDEX, Object, extension);
EXTRACT_CONTEXT_FIELD(GLOBAL_OBJECT_INDEX, GlobalObject, global);
if (context->IsNativeContext()) {
TagObject(context->jsfunction_result_caches(),
"(context func. result caches)");
TagObject(context->normalized_map_cache(), "(context norm. map cache)");
TagObject(context->runtime_context(), "(runtime context)");
TagObject(context->embedder_data(), "(context data)");

View File

@ -424,7 +424,6 @@ void Heap::IncrementDeferredCount(v8::Isolate::UseCounterFeature feature) {
void Heap::GarbageCollectionPrologue() {
{
AllowHeapAllocation for_the_first_part_of_prologue;
ClearJSFunctionResultCaches();
gc_count_++;
unflattened_strings_length_ = 0;
@ -1129,29 +1128,6 @@ void Heap::EnsureFromSpaceIsCommitted() {
}
void Heap::ClearJSFunctionResultCaches() {
if (isolate_->bootstrapper()->IsActive()) return;
Object* context = native_contexts_list();
while (!context->IsUndefined()) {
// Get the caches for this context. GC can happen when the context
// is not fully initialized, so the caches can be undefined.
Object* caches_or_undefined =
Context::cast(context)->get(Context::JSFUNCTION_RESULT_CACHES_INDEX);
if (!caches_or_undefined->IsUndefined()) {
FixedArray* caches = FixedArray::cast(caches_or_undefined);
// Clear the caches:
int length = caches->length();
for (int i = 0; i < length; i++) {
JSFunctionResultCache::cast(caches->get(i))->Clear();
}
}
// Get the next context:
context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
}
}
void Heap::ClearNormalizedMapCaches() {
if (isolate_->bootstrapper()->IsActive() &&
!incremental_marking()->IsMarking()) {

View File

@ -1341,8 +1341,6 @@ class Heap {
// scavenge operation.
inline bool ShouldBePromoted(Address old_address, int object_size);
void ClearJSFunctionResultCaches();
void ClearNormalizedMapCaches();
GCTracer* tracer() { return &tracer_; }

View File

@ -12500,12 +12500,6 @@ void HOptimizedGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) {
}
// Support for fast native caches.
void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) {
return Bailout(kInlinedRuntimeFunctionGetFromCache);
}
// Fast support for number to string.
void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) {
DCHECK_EQ(1, call->arguments()->length());

View File

@ -2212,7 +2212,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
F(StringCompare) \
F(RegExpExec) \
F(RegExpConstructResult) \
F(GetFromCache) \
F(NumberToString) \
F(DebugIsActive) \
F(Likely) \

View File

@ -1025,32 +1025,6 @@ void Script::ScriptVerify() {
}
void JSFunctionResultCache::JSFunctionResultCacheVerify() {
JSFunction::cast(get(kFactoryIndex))->ObjectVerify();
int size = Smi::cast(get(kCacheSizeIndex))->value();
CHECK(kEntriesIndex <= size);
CHECK(size <= length());
CHECK_EQ(0, size % kEntrySize);
int finger = Smi::cast(get(kFingerIndex))->value();
CHECK(kEntriesIndex <= finger);
CHECK((finger < size) || (finger == kEntriesIndex && finger == size));
CHECK_EQ(0, finger % kEntrySize);
if (FLAG_enable_slow_asserts) {
for (int i = kEntriesIndex; i < size; i++) {
CHECK(!get(i)->IsTheHole());
get(i)->ObjectVerify();
}
for (int i = size; i < length(); i++) {
CHECK(get(i)->IsTheHole());
get(i)->ObjectVerify();
}
}
}
void NormalizedMapCache::NormalizedMapCacheVerify() {
FixedArray::cast(this)->FixedArrayVerify();
if (FLAG_enable_slow_asserts) {

View File

@ -926,28 +926,6 @@ bool Object::IsStringTable() const {
}
bool Object::IsJSFunctionResultCache() const {
if (!IsFixedArray()) return false;
const FixedArray* self = FixedArray::cast(this);
int length = self->length();
if (length < JSFunctionResultCache::kEntriesIndex) return false;
if ((length - JSFunctionResultCache::kEntriesIndex)
% JSFunctionResultCache::kEntrySize != 0) {
return false;
}
#ifdef VERIFY_HEAP
if (FLAG_verify_heap) {
// TODO(svenpanne) We use const_cast here and below to break our dependency
// cycle between the predicates and the verifiers. This can be removed when
// the verifiers are const-correct, too.
reinterpret_cast<JSFunctionResultCache*>(const_cast<Object*>(this))->
JSFunctionResultCacheVerify();
}
#endif
return true;
}
bool Object::IsNormalizedMapCache() const {
return NormalizedMapCache::IsNormalizedMapCache(this);
}
@ -3124,7 +3102,6 @@ CAST_ACCESSOR(JSDataView)
CAST_ACCESSOR(JSDate)
CAST_ACCESSOR(JSFunction)
CAST_ACCESSOR(JSFunctionProxy)
CAST_ACCESSOR(JSFunctionResultCache)
CAST_ACCESSOR(JSGeneratorObject)
CAST_ACCESSOR(JSGlobalObject)
CAST_ACCESSOR(JSGlobalProxy)
@ -3721,42 +3698,6 @@ void StringCharacterStream::VisitTwoByteString(
}
void JSFunctionResultCache::MakeZeroSize() {
set_finger_index(kEntriesIndex);
set_size(kEntriesIndex);
}
void JSFunctionResultCache::Clear() {
int cache_size = size();
Object** entries_start = RawFieldOfElementAt(kEntriesIndex);
MemsetPointer(entries_start,
GetHeap()->the_hole_value(),
cache_size - kEntriesIndex);
MakeZeroSize();
}
int JSFunctionResultCache::size() {
return Smi::cast(get(kCacheSizeIndex))->value();
}
void JSFunctionResultCache::set_size(int size) {
set(kCacheSizeIndex, Smi::FromInt(size));
}
int JSFunctionResultCache::finger_index() {
return Smi::cast(get(kFingerIndex))->value();
}
void JSFunctionResultCache::set_finger_index(int finger_index) {
set(kFingerIndex, Smi::FromInt(finger_index));
}
byte ByteArray::get(int index) {
DCHECK(index >= 0 && index < this->length());
return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);

View File

@ -87,7 +87,6 @@
// - OrderedHashMap
// - Context
// - TypeFeedbackVector
// - JSFunctionResultCache
// - ScopeInfo
// - TransitionArray
// - ScriptContextTable
@ -986,7 +985,6 @@ template <class C> inline bool Is(Object* obj);
V(HashTable) \
V(Dictionary) \
V(StringTable) \
V(JSFunctionResultCache) \
V(NormalizedMapCache) \
V(CompilationCacheTable) \
V(CodeCacheHashTable) \
@ -3830,41 +3828,6 @@ class WeakValueHashTable : public ObjectHashTable {
};
// JSFunctionResultCache caches results of some JSFunction invocation.
// It is a fixed array with fixed structure:
// [0]: factory function
// [1]: finger index
// [2]: current cache size
// [3]: dummy field.
// The rest of array are key/value pairs.
class JSFunctionResultCache : public FixedArray {
public:
static const int kFactoryIndex = 0;
static const int kFingerIndex = kFactoryIndex + 1;
static const int kCacheSizeIndex = kFingerIndex + 1;
static const int kDummyIndex = kCacheSizeIndex + 1;
static const int kEntriesIndex = kDummyIndex + 1;
static const int kEntrySize = 2; // key + value
static const int kFactoryOffset = kHeaderSize;
static const int kFingerOffset = kFactoryOffset + kPointerSize;
static const int kCacheSizeOffset = kFingerOffset + kPointerSize;
inline void MakeZeroSize();
inline void Clear();
inline int size();
inline void set_size(int size);
inline int finger_index();
inline void set_finger_index(int finger_index);
DECLARE_CAST(JSFunctionResultCache)
DECLARE_VERIFIER(JSFunctionResultCache)
};
// ScopeInfo represents information about different scopes of a source
// program and the allocation of the scope's variables. Scope information
// is stored in a compressed form in ScopeInfo objects and is used

View File

@ -237,102 +237,6 @@ RUNTIME_FUNCTION(Runtime_RenderCallSite) {
}
RUNTIME_FUNCTION(Runtime_GetFromCacheRT) {
SealHandleScope shs(isolate);
// This is only called from codegen, so checks might be more lax.
CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
CONVERT_ARG_CHECKED(Object, key, 1);
{
DisallowHeapAllocation no_alloc;
int finger_index = cache->finger_index();
Object* o = cache->get(finger_index);
if (o == key) {
// The fastest case: hit the same place again.
return cache->get(finger_index + 1);
}
for (int i = finger_index - 2; i >= JSFunctionResultCache::kEntriesIndex;
i -= 2) {
o = cache->get(i);
if (o == key) {
cache->set_finger_index(i);
return cache->get(i + 1);
}
}
int size = cache->size();
DCHECK(size <= cache->length());
for (int i = size - 2; i > finger_index; i -= 2) {
o = cache->get(i);
if (o == key) {
cache->set_finger_index(i);
return cache->get(i + 1);
}
}
}
// There is no value in the cache. Invoke the function and cache result.
HandleScope scope(isolate);
Handle<JSFunctionResultCache> cache_handle(cache);
Handle<Object> key_handle(key, isolate);
Handle<Object> value;
{
Handle<JSFunction> factory(JSFunction::cast(
cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
// TODO(antonm): consider passing a receiver when constructing a cache.
Handle<JSObject> receiver(isolate->global_proxy());
// This handle is nor shared, nor used later, so it's safe.
Handle<Object> argv[] = {key_handle};
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, value,
Execution::Call(isolate, factory, receiver, arraysize(argv), argv));
}
#ifdef VERIFY_HEAP
if (FLAG_verify_heap) {
cache_handle->JSFunctionResultCacheVerify();
}
#endif
// Function invocation may have cleared the cache. Reread all the data.
int finger_index = cache_handle->finger_index();
int size = cache_handle->size();
// If we have spare room, put new data into it, otherwise evict post finger
// entry which is likely to be the least recently used.
int index = -1;
if (size < cache_handle->length()) {
cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
index = size;
} else {
index = finger_index + JSFunctionResultCache::kEntrySize;
if (index == cache_handle->length()) {
index = JSFunctionResultCache::kEntriesIndex;
}
}
DCHECK(index % 2 == 0);
DCHECK(index >= JSFunctionResultCache::kEntriesIndex);
DCHECK(index < cache_handle->length());
cache_handle->set(index, *key_handle);
cache_handle->set(index + 1, *value);
cache_handle->set_finger_index(index);
#ifdef VERIFY_HEAP
if (FLAG_verify_heap) {
cache_handle->JSFunctionResultCacheVerify();
}
#endif
return *value;
}
RUNTIME_FUNCTION(Runtime_MessageGetStartPosition) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
@ -413,15 +317,6 @@ RUNTIME_FUNCTION(Runtime_IS_VAR) {
}
RUNTIME_FUNCTION(Runtime_GetFromCache) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_SMI_ARG_CHECKED(id, 0);
args[0] = isolate->native_context()->jsfunction_result_caches()->get(id);
return __RT_impl_Runtime_GetFromCacheRT(args, isolate);
}
RUNTIME_FUNCTION(Runtime_IncrementStatsCounter) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);

View File

@ -321,7 +321,6 @@ namespace internal {
F(AllocateInTargetSpace, 2, 1) \
F(CollectStackTrace, 2, 1) \
F(RenderCallSite, 0, 1) \
F(GetFromCacheRT, 2, 1) \
F(MessageGetStartPosition, 1, 1) \
F(MessageGetScript, 1, 1) \
F(FormatMessageString, 4, 1) \
@ -336,7 +335,6 @@ namespace internal {
F(CallSiteIsEvalRT, 3, 1) \
F(CallSiteIsConstructorRT, 3, 1) \
F(IS_VAR, 1, 1) \
F(GetFromCache, 2, 1) \
F(IncrementStatsCounter, 1, 1) \
F(Likely, 1, 1) \
F(Unlikely, 1, 1) \

View File

@ -546,9 +546,7 @@ function StringSearch(re) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.search");
var regexp;
if (IS_STRING(re)) {
regexp = %_GetFromCache(STRING_TO_REGEXP_CACHE_ID, re);
} else if (IS_REGEXP(re)) {
if (IS_REGEXP(re)) {
regexp = re;
} else {
regexp = new GlobalRegExp(re);

View File

@ -97,7 +97,12 @@ void CcTest::Run() {
}
callback_();
if (initialize_) {
EmptyMessageQueues(isolate_);
if (v8::Locker::IsActive()) {
v8::Locker locker(isolate_);
EmptyMessageQueues(isolate_);
} else {
EmptyMessageQueues(isolate_);
}
isolate_->Exit();
}
}

View File

@ -6787,6 +6787,7 @@ static void ForceMarkSweep1(
THREADED_TEST(GCFromWeakCallbacks) {
v8::Isolate* isolate = CcTest::isolate();
v8::Locker locker(CcTest::isolate());
v8::HandleScope scope(isolate);
v8::Handle<Context> context = Context::New(isolate);
Context::Scope context_scope(context);
@ -11923,6 +11924,7 @@ void HandleCreatingCallback1(
THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
v8::Locker locker(CcTest::isolate());
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
@ -16565,118 +16567,6 @@ TEST(GCCallbacks) {
}
THREADED_TEST(AddToJSFunctionResultCache) {
i::FLAG_stress_compaction = false;
i::FLAG_allow_natives_syntax = true;
v8::HandleScope scope(CcTest::isolate());
LocalContext context;
const char* code =
"(function() {"
" var key0 = 'a';"
" var key1 = 'b';"
" var r0 = %_GetFromCache(0, key0);"
" var r1 = %_GetFromCache(0, key1);"
" var r0_ = %_GetFromCache(0, key0);"
" if (r0 !== r0_)"
" return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
" var r1_ = %_GetFromCache(0, key1);"
" if (r1 !== r1_)"
" return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
" return 'PASSED';"
"})()";
CcTest::heap()->ClearJSFunctionResultCaches();
ExpectString(code, "PASSED");
}
THREADED_TEST(FillJSFunctionResultCache) {
i::FLAG_allow_natives_syntax = true;
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
const char* code =
"(function() {"
" var k = 'a';"
" var r = %_GetFromCache(0, k);"
" for (var i = 0; i < 16; i++) {"
" %_GetFromCache(0, 'a' + i);"
" };"
" if (r === %_GetFromCache(0, k))"
" return 'FAILED: k0CacheSize is too small';"
" return 'PASSED';"
"})()";
CcTest::heap()->ClearJSFunctionResultCaches();
ExpectString(code, "PASSED");
}
THREADED_TEST(RoundRobinGetFromCache) {
i::FLAG_allow_natives_syntax = true;
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
const char* code =
"(function() {"
" var keys = [];"
" for (var i = 0; i < 16; i++) keys.push(i);"
" var values = [];"
" for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
" for (var i = 0; i < 16; i++) {"
" var v = %_GetFromCache(0, keys[i]);"
" if (v.toString() !== values[i].toString())"
" return 'Wrong value for ' + "
" keys[i] + ': ' + v + ' vs. ' + values[i];"
" };"
" return 'PASSED';"
"})()";
CcTest::heap()->ClearJSFunctionResultCaches();
ExpectString(code, "PASSED");
}
THREADED_TEST(ReverseGetFromCache) {
i::FLAG_allow_natives_syntax = true;
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
const char* code =
"(function() {"
" var keys = [];"
" for (var i = 0; i < 16; i++) keys.push(i);"
" var values = [];"
" for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
" for (var i = 15; i >= 16; i--) {"
" var v = %_GetFromCache(0, keys[i]);"
" if (v !== values[i])"
" return 'Wrong value for ' + "
" keys[i] + ': ' + v + ' vs. ' + values[i];"
" };"
" return 'PASSED';"
"})()";
CcTest::heap()->ClearJSFunctionResultCaches();
ExpectString(code, "PASSED");
}
THREADED_TEST(TestEviction) {
i::FLAG_allow_natives_syntax = true;
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
const char* code =
"(function() {"
" for (var i = 0; i < 2*16; i++) {"
" %_GetFromCache(0, 'a' + i);"
" };"
" return 'PASSED';"
"})()";
CcTest::heap()->ClearJSFunctionResultCaches();
ExpectString(code, "PASSED");
}
THREADED_TEST(TwoByteStringInOneByteCons) {
// See Chromium issue 47824.
LocalContext context;

View File

@ -32,88 +32,6 @@
#include "src/isolate.h"
enum Turn { FILL_CACHE, CLEAN_CACHE, SECOND_TIME_FILL_CACHE, CACHE_DONE };
static Turn turn = FILL_CACHE;
class ThreadA : public v8::base::Thread {
public:
ThreadA() : Thread(Options("ThreadA")) {}
void Run() {
v8::Isolate* isolate = CcTest::isolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope scope(isolate);
v8::Handle<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
CHECK_EQ(FILL_CACHE, turn);
// Fill String.search cache.
v8::Handle<v8::Script> script = v8::Script::Compile(
v8::String::NewFromUtf8(
isolate,
"for (var i = 0; i < 3; i++) {"
" var result = \"a\".search(\"a\");"
" if (result != 0) throw \"result: \" + result + \" @\" + i;"
"};"
"true"));
CHECK(script->Run()->IsTrue());
turn = CLEAN_CACHE;
do {
{
v8::Unlocker unlocker(CcTest::isolate());
}
} while (turn != SECOND_TIME_FILL_CACHE);
// Rerun the script.
CHECK(script->Run()->IsTrue());
turn = CACHE_DONE;
}
};
class ThreadB : public v8::base::Thread {
public:
ThreadB() : Thread(Options("ThreadB")) {}
void Run() {
do {
{
v8::Isolate* isolate = CcTest::isolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolate_scope(isolate);
if (turn == CLEAN_CACHE) {
v8::HandleScope scope(isolate);
v8::Handle<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
// Clear the caches by forcing major GC.
CcTest::heap()->CollectAllGarbage();
turn = SECOND_TIME_FILL_CACHE;
break;
}
}
} while (true);
}
};
TEST(JSFunctionResultCachesInTwoThreads) {
ThreadA threadA;
ThreadB threadB;
threadA.Start();
threadB.Start();
threadA.Join();
threadB.Join();
CHECK_EQ(CACHE_DONE, turn);
}
class ThreadIdValidationThread : public v8::base::Thread {
public:
ThreadIdValidationThread(v8::base::Thread* thread_to_start,