Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(473)

Unified Diff: src/interpreter/interpreter.cc

Issue 2155153002: [interpreter] Update ForInPrepare to conditionally use runtime. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Rebase Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/interpreter/interpreter.cc
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index 4830f1dc72efa1f90dfece7c047bee278d960916..a890591e5afc433f909e2ea1ebc366f410400d4d 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -1840,6 +1840,17 @@ void Interpreter::DoDebugger(InterpreterAssembler* assembler) {
DEBUG_BREAK_BYTECODE_LIST(DEBUG_BREAK);
#undef DEBUG_BREAK
+void Interpreter::BuildForInPrepareResult(Node* output_register,
+ Node* cache_type, Node* cache_array,
+ Node* cache_length,
+ InterpreterAssembler* assembler) {
+ __ StoreRegister(cache_type, output_register);
+ output_register = __ NextRegister(output_register);
+ __ StoreRegister(cache_array, output_register);
+ output_register = __ NextRegister(output_register);
+ __ StoreRegister(cache_length, output_register);
+}
+
// ForInPrepare <cache_info_triple>
//
// Returns state for for..in loop execution based on the object in the
@@ -1849,17 +1860,93 @@ DEBUG_BREAK_BYTECODE_LIST(DEBUG_BREAK);
void Interpreter::DoForInPrepare(InterpreterAssembler* assembler) {
Node* object = __ GetAccumulator();
Node* context = __ GetContext();
- Node* result_triple = __ CallRuntime(Runtime::kForInPrepare, context, object);
-
- // Set output registers:
- // 0 == cache_type, 1 == cache_array, 2 == cache_length
- Node* output_register = __ BytecodeOperandReg(0);
- for (int i = 0; i < 3; i++) {
- Node* cache_info = __ Projection(i, result_triple);
- __ StoreRegister(cache_info, output_register);
- output_register = __ NextRegister(output_register);
+ Node* const zero_smi = __ SmiConstant(Smi::FromInt(0));
+
+ Label test_if_null(assembler), test_if_undefined(assembler),
+ nothing_to_iterate(assembler, Label::kDeferred),
rmcilroy 2016/07/19 11:08:54 Just wondering if nothing_to_iterate should be kDe
oth 2016/07/19 12:59:25 I expect this is the lesser trodden path - it's de
+ convert_to_receiver(assembler), already_receiver(assembler),
+ check_enum_cache(assembler);
+
+ Variable receiver(assembler, MachineRepresentation::kTagged);
+
+ // Test if object is already a receiver, no conversion necessary if so.
+ Node* instance_type = __ LoadInstanceType(object);
+ Node* first_receiver_type = __ Int32Constant(FIRST_JS_RECEIVER_TYPE);
+ __ BranchIf(
+ assembler->Int32GreaterThanOrEqual(instance_type, first_receiver_type),
rmcilroy 2016/07/19 11:08:54 There is a BranchIfInt32GreaterThanOrEqual (I thin
oth 2016/07/19 12:59:25 Thanks! Done.
+ &already_receiver, &test_if_null);
+
+ __ Bind(&test_if_null);
+ {
+ __ BranchIf(assembler->WordEqual(object, assembler->NullConstant()),
rmcilroy 2016/07/19 11:08:54 BranchIfWordEqual (and below)
oth 2016/07/19 12:59:25 Done.
+ &nothing_to_iterate, &test_if_undefined);
+ }
+
+ __ Bind(&test_if_undefined);
+ {
+ __ BranchIf(assembler->WordEqual(object, assembler->UndefinedConstant()),
+ &nothing_to_iterate, &convert_to_receiver);
+ }
+
+ __ Bind(&convert_to_receiver);
rmcilroy 2016/07/19 11:08:54 I'm assuming this is relatively uncommon. If so, c
oth 2016/07/19 12:59:25 Done.
+ {
+ Callable callable = CodeFactory::ToObject(assembler->isolate());
+ Node* target = __ HeapConstant(callable.code());
+ Node* result = __ CallStub(callable.descriptor(), target, context, object);
+ receiver.Bind(result);
+ __ Goto(&check_enum_cache);
+ }
+
+ __ Bind(&already_receiver);
+ {
+ receiver.Bind(object);
+ __ Goto(&check_enum_cache);
+ }
+
+ Label use_enum_cache(assembler), use_runtime(assembler);
rmcilroy 2016/07/19 11:08:54 make use_runtime kDeferred.
oth 2016/07/19 12:59:25 Done.
+ __ Bind(&check_enum_cache);
+ { __ CheckEnumCache(receiver.value(), &use_enum_cache, &use_runtime); }
+
+ __ Bind(&use_enum_cache);
+ {
+ // The enum cache is valid. Load the map of the object being
+ // iterated over and use the cache for the iteration.
+ Node* cache_type = __ LoadMap(receiver.value());
+ Node* cache_length = __ EnumLength(cache_type);
+ __ GotoIf(assembler->WordEqual(cache_length, zero_smi),
+ &nothing_to_iterate);
+ Node* descriptors = __ LoadMapDescriptors(cache_type);
+ Node* cache_offset =
+ __ LoadObjectField(descriptors, DescriptorArray::kEnumCacheOffset);
+ Node* cache_array = __ LoadObjectField(
+ cache_offset, DescriptorArray::kEnumCacheBridgeCacheOffset);
+ Node* output_register = __ BytecodeOperandReg(0);
+ BuildForInPrepareResult(output_register, cache_type, cache_array,
+ cache_length, assembler);
+ __ Dispatch();
+ }
+
+ __ Bind(&use_runtime);
+ {
+ Node* result_triple =
+ __ CallRuntime(Runtime::kForInPrepare, context, object);
+ Node* cache_type = __ Projection(0, result_triple);
+ Node* cache_array = __ Projection(1, result_triple);
+ Node* cache_length = __ Projection(2, result_triple);
+ Node* output_register = __ BytecodeOperandReg(0);
+ BuildForInPrepareResult(output_register, cache_type, cache_array,
+ cache_length, assembler);
+ __ Dispatch();
+ }
+
+ __ Bind(&nothing_to_iterate);
+ {
+ // Receiver is null or undefined or descriptors are zero length.
+ Node* output_register = __ BytecodeOperandReg(0);
+ BuildForInPrepareResult(output_register, zero_smi, zero_smi, zero_smi,
+ assembler);
+ __ Dispatch();
}
- __ Dispatch();
}
// ForInNext <receiver> <index> <cache_info_pair>

Powered by Google App Engine
This is Rietveld 408576698