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:
parent
8d2eec506f
commit
4a2e4420b8
@ -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;
|
||||
|
@ -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") \
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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, ¬_found);
|
||||
|
||||
__ ldr(r0, MemOperand(r3, kPointerSize));
|
||||
__ b(&done);
|
||||
|
||||
__ bind(¬_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));
|
||||
|
@ -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));
|
||||
|
@ -530,7 +530,6 @@ class FullCodeGenerator: public AstVisitor {
|
||||
F(StringCompare) \
|
||||
F(RegExpExec) \
|
||||
F(RegExpConstructResult) \
|
||||
F(GetFromCache) \
|
||||
F(NumberToString) \
|
||||
F(ToObject) \
|
||||
F(DebugIsActive)
|
||||
|
@ -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, ¬_found);
|
||||
|
||||
__ mov(eax, FixedArrayElementOperand(cache, tmp, 1));
|
||||
__ jmp(&done);
|
||||
|
||||
__ bind(¬_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);
|
||||
|
@ -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(¬_found, ne, key, Operand(a2));
|
||||
|
||||
__ lw(v0, MemOperand(a3, kPointerSize));
|
||||
__ Branch(&done);
|
||||
|
||||
__ bind(¬_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));
|
||||
|
@ -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(¬_found, ne, key, Operand(a2));
|
||||
|
||||
__ ld(v0, MemOperand(a3, kPointerSize));
|
||||
__ Branch(&done);
|
||||
|
||||
__ bind(¬_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));
|
||||
|
@ -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(¬_found);
|
||||
|
||||
__ LoadP(r3, MemOperand(r6, kPointerSize));
|
||||
__ b(&done);
|
||||
|
||||
__ bind(¬_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));
|
||||
|
@ -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, ¬_found, Label::kNear);
|
||||
__ movp(rax, FieldOperand(cache,
|
||||
index.reg,
|
||||
index.scale,
|
||||
FixedArray::kHeaderSize + kPointerSize));
|
||||
__ jmp(&done, Label::kNear);
|
||||
|
||||
__ bind(¬_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);
|
||||
|
@ -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, ¬_found);
|
||||
|
||||
__ mov(eax, FixedArrayElementOperand(cache, tmp, 1));
|
||||
__ jmp(&done);
|
||||
|
||||
__ bind(¬_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);
|
||||
|
@ -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)");
|
||||
|
@ -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()) {
|
||||
|
@ -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_; }
|
||||
|
@ -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());
|
||||
|
@ -2212,7 +2212,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
F(StringCompare) \
|
||||
F(RegExpExec) \
|
||||
F(RegExpConstructResult) \
|
||||
F(GetFromCache) \
|
||||
F(NumberToString) \
|
||||
F(DebugIsActive) \
|
||||
F(Likely) \
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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) \
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user