[es6] Introduce a dedicated JSIteratorResult type.
Use a single JSIteratorResult type for all implementation provided iterator results (i.e. the String, Array and collection iterators, and also for generators). This removes one source of unnecessary polymorphism in for-of loops. It is accomplished by a new intrinsic %_CreateIterResultObject() that should be used to create iterator result objects from JavaScript builtins (there's a matching factory method for C++ code). Also restructure the %StringIteratorPrototype%.next() and %ArrayIteratorPrototype%.next() functions to be a bit more friendly to optimizing compilers. R=ishell@chromium.org Review URL: https://codereview.chromium.org/1302173007 Cr-Commit-Position: refs/heads/master@{#30557}
This commit is contained in:
parent
c8dbd2c477
commit
72bc4b5c8a
@ -62,21 +62,17 @@ function CreateArrayIterator(array, kind) {
|
||||
}
|
||||
|
||||
|
||||
// 15.19.4.3.4 CreateItrResultObject
|
||||
function CreateIteratorResultObject(value, done) {
|
||||
return {value: value, done: done};
|
||||
}
|
||||
|
||||
|
||||
// 22.1.5.2.2 %ArrayIteratorPrototype%[@@iterator]
|
||||
function ArrayIteratorIterator() {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// 15.4.5.2.2 ArrayIterator.prototype.next( )
|
||||
// ES6 section 22.1.5.2.1 %ArrayIteratorPrototype%.next( )
|
||||
function ArrayIteratorNext() {
|
||||
var iterator = this;
|
||||
var value = UNDEFINED;
|
||||
var done = true;
|
||||
|
||||
if (!IS_SPEC_OBJECT(iterator) ||
|
||||
!HAS_DEFINED_PRIVATE(iterator, arrayIteratorNextIndexSymbol)) {
|
||||
@ -85,32 +81,30 @@ function ArrayIteratorNext() {
|
||||
}
|
||||
|
||||
var array = GET_PRIVATE(iterator, arrayIteratorObjectSymbol);
|
||||
if (IS_UNDEFINED(array)) {
|
||||
return CreateIteratorResultObject(UNDEFINED, true);
|
||||
if (!IS_UNDEFINED(array)) {
|
||||
var index = GET_PRIVATE(iterator, arrayIteratorNextIndexSymbol);
|
||||
var itemKind = GET_PRIVATE(iterator, arrayIterationKindSymbol);
|
||||
var length = TO_UINT32(array.length);
|
||||
|
||||
// "sparse" is never used.
|
||||
|
||||
if (index >= length) {
|
||||
SET_PRIVATE(iterator, arrayIteratorObjectSymbol, UNDEFINED);
|
||||
} else {
|
||||
SET_PRIVATE(iterator, arrayIteratorNextIndexSymbol, index + 1);
|
||||
|
||||
if (itemKind == ITERATOR_KIND_VALUES) {
|
||||
value = array[index];
|
||||
} else if (itemKind == ITERATOR_KIND_ENTRIES) {
|
||||
value = [index, array[index]];
|
||||
} else {
|
||||
value = index;
|
||||
}
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
|
||||
var index = GET_PRIVATE(iterator, arrayIteratorNextIndexSymbol);
|
||||
var itemKind = GET_PRIVATE(iterator, arrayIterationKindSymbol);
|
||||
var length = TO_UINT32(array.length);
|
||||
|
||||
// "sparse" is never used.
|
||||
|
||||
if (index >= length) {
|
||||
SET_PRIVATE(iterator, arrayIteratorObjectSymbol, UNDEFINED);
|
||||
return CreateIteratorResultObject(UNDEFINED, true);
|
||||
}
|
||||
|
||||
SET_PRIVATE(iterator, arrayIteratorNextIndexSymbol, index + 1);
|
||||
|
||||
if (itemKind == ITERATOR_KIND_VALUES) {
|
||||
return CreateIteratorResultObject(array[index], false);
|
||||
}
|
||||
|
||||
if (itemKind == ITERATOR_KIND_ENTRIES) {
|
||||
return CreateIteratorResultObject([index, array[index]], false);
|
||||
}
|
||||
|
||||
return CreateIteratorResultObject(index, false);
|
||||
return %_CreateIterResultObject(value, done);
|
||||
}
|
||||
|
||||
|
||||
@ -167,10 +161,6 @@ TYPED_ARRAYS(EXTEND_TYPED_ARRAY)
|
||||
// -------------------------------------------------------------------
|
||||
// Exports
|
||||
|
||||
utils.Export(function(to) {
|
||||
to.ArrayIteratorCreateResultObject = CreateIteratorResultObject;
|
||||
});
|
||||
|
||||
$arrayValues = ArrayValues;
|
||||
|
||||
%InstallToContext(["array_values_iterator", ArrayValues]);
|
||||
|
@ -1312,32 +1312,26 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
|
||||
native_context()->set_js_set_fun(*js_set_fun);
|
||||
}
|
||||
|
||||
{ // Set up the iterator result object
|
||||
STATIC_ASSERT(JSGeneratorObject::kResultPropertyCount == 2);
|
||||
Handle<JSFunction> object_function(native_context()->object_function());
|
||||
Handle<Map> iterator_result_map =
|
||||
Map::Create(isolate, JSGeneratorObject::kResultPropertyCount);
|
||||
DCHECK_EQ(JSGeneratorObject::kResultSize,
|
||||
iterator_result_map->instance_size());
|
||||
DCHECK_EQ(JSGeneratorObject::kResultPropertyCount,
|
||||
iterator_result_map->GetInObjectProperties());
|
||||
Map::EnsureDescriptorSlack(iterator_result_map,
|
||||
JSGeneratorObject::kResultPropertyCount);
|
||||
{ // -- I t e r a t o r R e s u l t
|
||||
Handle<Map> map =
|
||||
factory->NewMap(JS_ITERATOR_RESULT_TYPE, JSIteratorResult::kSize);
|
||||
Map::SetPrototype(map, isolate->initial_object_prototype());
|
||||
Map::EnsureDescriptorSlack(map, 2);
|
||||
|
||||
DataDescriptor value_descr(factory->value_string(),
|
||||
JSGeneratorObject::kResultValuePropertyIndex,
|
||||
NONE, Representation::Tagged());
|
||||
iterator_result_map->AppendDescriptor(&value_descr);
|
||||
{ // value
|
||||
DataDescriptor d(factory->value_string(), JSIteratorResult::kValueIndex,
|
||||
NONE, Representation::Tagged());
|
||||
map->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
DataDescriptor done_descr(factory->done_string(),
|
||||
JSGeneratorObject::kResultDonePropertyIndex, NONE,
|
||||
Representation::Tagged());
|
||||
iterator_result_map->AppendDescriptor(&done_descr);
|
||||
{ // done
|
||||
DataDescriptor d(factory->done_string(), JSIteratorResult::kDoneIndex,
|
||||
NONE, Representation::Tagged());
|
||||
map->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
iterator_result_map->set_unused_property_fields(0);
|
||||
DCHECK_EQ(JSGeneratorObject::kResultSize,
|
||||
iterator_result_map->instance_size());
|
||||
native_context()->set_iterator_result_map(*iterator_result_map);
|
||||
map->SetInObjectProperties(2);
|
||||
native_context()->set_iterator_result_map(*map);
|
||||
}
|
||||
|
||||
// -- W e a k M a p
|
||||
|
@ -32,21 +32,21 @@ function SetIteratorNextJS() {
|
||||
}
|
||||
|
||||
var value_array = [UNDEFINED, UNDEFINED];
|
||||
var entry = {value: value_array, done: false};
|
||||
var result = %_CreateIterResultObject(value_array, false);
|
||||
switch (%SetIteratorNext(this, value_array)) {
|
||||
case 0:
|
||||
entry.value = UNDEFINED;
|
||||
entry.done = true;
|
||||
result.value = UNDEFINED;
|
||||
result.done = true;
|
||||
break;
|
||||
case ITERATOR_KIND_VALUES:
|
||||
entry.value = value_array[0];
|
||||
result.value = value_array[0];
|
||||
break;
|
||||
case ITERATOR_KIND_ENTRIES:
|
||||
value_array[1] = value_array[0];
|
||||
break;
|
||||
}
|
||||
|
||||
return entry;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -104,22 +104,22 @@ function MapIteratorNextJS() {
|
||||
}
|
||||
|
||||
var value_array = [UNDEFINED, UNDEFINED];
|
||||
var entry = {value: value_array, done: false};
|
||||
var result = %_CreateIterResultObject(value_array, false);
|
||||
switch (%MapIteratorNext(this, value_array)) {
|
||||
case 0:
|
||||
entry.value = UNDEFINED;
|
||||
entry.done = true;
|
||||
result.value = UNDEFINED;
|
||||
result.done = true;
|
||||
break;
|
||||
case ITERATOR_KIND_KEYS:
|
||||
entry.value = value_array[0];
|
||||
result.value = value_array[0];
|
||||
break;
|
||||
case ITERATOR_KIND_VALUES:
|
||||
entry.value = value_array[1];
|
||||
result.value = value_array[1];
|
||||
break;
|
||||
// ITERATOR_KIND_ENTRIES does not need any processing.
|
||||
}
|
||||
|
||||
return entry;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -247,6 +247,7 @@ enum BindingFlags {
|
||||
V(JS_SET_MAP_INDEX, Map, js_set_map) \
|
||||
V(MAP_CACHE_INDEX, Object, map_cache) \
|
||||
V(MAP_ITERATOR_MAP_INDEX, Map, map_iterator_map) \
|
||||
V(STRING_ITERATOR_MAP_INDEX, Map, string_iterator_map) \
|
||||
V(MESSAGE_LISTENERS_INDEX, JSObject, message_listeners) \
|
||||
V(NATIVES_UTILS_OBJECT_INDEX, Object, natives_utils_object) \
|
||||
V(NORMALIZED_MAP_CACHE_INDEX, Object, normalized_map_cache) \
|
||||
|
@ -1680,6 +1680,16 @@ Handle<JSSetIterator> Factory::NewJSSetIterator() {
|
||||
}
|
||||
|
||||
|
||||
Handle<JSIteratorResult> Factory::NewJSIteratorResult(Handle<Object> value,
|
||||
Handle<Object> done) {
|
||||
Handle<JSIteratorResult> result = Handle<JSIteratorResult>::cast(
|
||||
NewJSObjectFromMap(isolate()->iterator_result_map()));
|
||||
result->set_value(*value);
|
||||
result->set_done(*done);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
ElementsKind GetExternalArrayElementsKind(ExternalArrayType type) {
|
||||
|
@ -475,6 +475,11 @@ class Factory final {
|
||||
Handle<JSMapIterator> NewJSMapIterator();
|
||||
Handle<JSSetIterator> NewJSSetIterator();
|
||||
|
||||
// Creates a new JSIteratorResult object with the arguments {value} and
|
||||
// {done}. Implemented according to ES6 section 7.4.7 CreateIterResultObject.
|
||||
Handle<JSIteratorResult> NewJSIteratorResult(Handle<Object> value,
|
||||
Handle<Object> done);
|
||||
|
||||
// Allocates a Harmony proxy.
|
||||
Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype);
|
||||
|
||||
|
@ -2275,41 +2275,28 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
|
||||
Label gc_required;
|
||||
Label allocated;
|
||||
Label allocate, done_allocate;
|
||||
|
||||
const int instance_size = 5 * kPointerSize;
|
||||
DCHECK_EQ(isolate()->native_context()->iterator_result_map()->instance_size(),
|
||||
instance_size);
|
||||
__ Allocate(JSIteratorResult::kSize, r0, r2, r3, &allocate, TAG_OBJECT);
|
||||
__ b(&done_allocate);
|
||||
|
||||
__ Allocate(instance_size, r0, r2, r3, &gc_required, TAG_OBJECT);
|
||||
__ jmp(&allocated);
|
||||
|
||||
__ bind(&gc_required);
|
||||
__ Push(Smi::FromInt(instance_size));
|
||||
__ bind(&allocate);
|
||||
__ Push(Smi::FromInt(JSIteratorResult::kSize));
|
||||
__ CallRuntime(Runtime::kAllocateInNewSpace, 1);
|
||||
__ ldr(context_register(),
|
||||
MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||
|
||||
__ bind(&allocated);
|
||||
__ bind(&done_allocate);
|
||||
__ ldr(r1, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kNativeContextOffset));
|
||||
__ ldr(r1, ContextOperand(r1, Context::ITERATOR_RESULT_MAP_INDEX));
|
||||
__ pop(r2);
|
||||
__ mov(r3, Operand(isolate()->factory()->ToBoolean(done)));
|
||||
__ mov(r4, Operand(isolate()->factory()->empty_fixed_array()));
|
||||
__ LoadRoot(r3,
|
||||
done ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex);
|
||||
__ LoadRoot(r4, Heap::kEmptyFixedArrayRootIndex);
|
||||
__ str(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
|
||||
__ str(r4, FieldMemOperand(r0, JSObject::kPropertiesOffset));
|
||||
__ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
|
||||
__ str(r2,
|
||||
FieldMemOperand(r0, JSGeneratorObject::kResultValuePropertyOffset));
|
||||
__ str(r3,
|
||||
FieldMemOperand(r0, JSGeneratorObject::kResultDonePropertyOffset));
|
||||
|
||||
// Only the value field needs a write barrier, as the other values are in the
|
||||
// root set.
|
||||
__ RecordWriteField(r0, JSGeneratorObject::kResultValuePropertyOffset,
|
||||
r2, r3, kLRHasBeenSaved, kDontSaveFPRegs);
|
||||
__ str(r2, FieldMemOperand(r0, JSIteratorResult::kValueOffset));
|
||||
__ str(r3, FieldMemOperand(r0, JSIteratorResult::kDoneOffset));
|
||||
}
|
||||
|
||||
|
||||
@ -4473,6 +4460,37 @@ void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitCreateIterResultObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK_EQ(2, args->length());
|
||||
VisitForStackValue(args->at(0));
|
||||
VisitForStackValue(args->at(1));
|
||||
|
||||
Label runtime, done;
|
||||
|
||||
__ Allocate(JSIteratorResult::kSize, r0, r2, r3, &runtime, TAG_OBJECT);
|
||||
__ ldr(r1, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kNativeContextOffset));
|
||||
__ ldr(r1, ContextOperand(r1, Context::ITERATOR_RESULT_MAP_INDEX));
|
||||
__ pop(r3);
|
||||
__ pop(r2);
|
||||
__ LoadRoot(r4, Heap::kEmptyFixedArrayRootIndex);
|
||||
__ str(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
|
||||
__ str(r4, FieldMemOperand(r0, JSObject::kPropertiesOffset));
|
||||
__ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
|
||||
__ str(r2, FieldMemOperand(r0, JSIteratorResult::kValueOffset));
|
||||
__ str(r3, FieldMemOperand(r0, JSIteratorResult::kDoneOffset));
|
||||
STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
|
||||
__ b(&done);
|
||||
|
||||
__ bind(&runtime);
|
||||
__ CallRuntime(Runtime::kCreateIterResultObject, 2);
|
||||
|
||||
__ bind(&done);
|
||||
context()->Plug(r0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) {
|
||||
// Push undefined as the receiver.
|
||||
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
|
||||
|
@ -4172,6 +4172,49 @@ void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitCreateIterResultObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK_EQ(2, args->length());
|
||||
VisitForStackValue(args->at(0));
|
||||
VisitForStackValue(args->at(1));
|
||||
|
||||
Label runtime, done;
|
||||
|
||||
Register result = x0;
|
||||
__ Allocate(JSIteratorResult::kSize, result, x10, x11, &runtime, TAG_OBJECT);
|
||||
Register map_reg = x1;
|
||||
Register result_value = x2;
|
||||
Register boolean_done = x3;
|
||||
Register empty_fixed_array = x4;
|
||||
Register untagged_result = x5;
|
||||
__ Ldr(map_reg, GlobalObjectMemOperand());
|
||||
__ Ldr(map_reg, FieldMemOperand(map_reg, GlobalObject::kNativeContextOffset));
|
||||
__ Ldr(map_reg,
|
||||
ContextMemOperand(map_reg, Context::ITERATOR_RESULT_MAP_INDEX));
|
||||
__ Pop(boolean_done);
|
||||
__ Pop(result_value);
|
||||
__ LoadRoot(empty_fixed_array, Heap::kEmptyFixedArrayRootIndex);
|
||||
STATIC_ASSERT(JSObject::kPropertiesOffset + kPointerSize ==
|
||||
JSObject::kElementsOffset);
|
||||
STATIC_ASSERT(JSIteratorResult::kValueOffset + kPointerSize ==
|
||||
JSIteratorResult::kDoneOffset);
|
||||
__ ObjectUntag(untagged_result, result);
|
||||
__ Str(map_reg, MemOperand(untagged_result, HeapObject::kMapOffset));
|
||||
__ Stp(empty_fixed_array, empty_fixed_array,
|
||||
MemOperand(untagged_result, JSObject::kPropertiesOffset));
|
||||
__ Stp(result_value, boolean_done,
|
||||
MemOperand(untagged_result, JSIteratorResult::kValueOffset));
|
||||
STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
|
||||
__ B(&done);
|
||||
|
||||
__ Bind(&runtime);
|
||||
__ CallRuntime(Runtime::kCreateIterResultObject, 2);
|
||||
|
||||
__ Bind(&done);
|
||||
context()->Plug(x0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) {
|
||||
// Push undefined as the receiver.
|
||||
__ LoadRoot(x0, Heap::kUndefinedValueRootIndex);
|
||||
@ -5081,26 +5124,19 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
|
||||
Label gc_required;
|
||||
Label allocated;
|
||||
|
||||
const int instance_size = 5 * kPointerSize;
|
||||
DCHECK_EQ(isolate()->native_context()->iterator_result_map()->instance_size(),
|
||||
instance_size);
|
||||
Label allocate, done_allocate;
|
||||
|
||||
// Allocate and populate an object with this form: { value: VAL, done: DONE }
|
||||
|
||||
Register result = x0;
|
||||
__ Allocate(instance_size, result, x10, x11, &gc_required, TAG_OBJECT);
|
||||
__ B(&allocated);
|
||||
__ Allocate(JSIteratorResult::kSize, result, x10, x11, &allocate, TAG_OBJECT);
|
||||
__ B(&done_allocate);
|
||||
|
||||
__ Bind(&gc_required);
|
||||
__ Push(Smi::FromInt(instance_size));
|
||||
__ Bind(&allocate);
|
||||
__ Push(Smi::FromInt(JSIteratorResult::kSize));
|
||||
__ CallRuntime(Runtime::kAllocateInNewSpace, 1);
|
||||
__ Ldr(context_register(),
|
||||
MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||
|
||||
__ Bind(&allocated);
|
||||
__ Bind(&done_allocate);
|
||||
Register map_reg = x1;
|
||||
Register result_value = x2;
|
||||
Register boolean_done = x3;
|
||||
@ -5111,24 +5147,20 @@ void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
|
||||
__ Ldr(map_reg,
|
||||
ContextMemOperand(map_reg, Context::ITERATOR_RESULT_MAP_INDEX));
|
||||
__ Pop(result_value);
|
||||
__ Mov(boolean_done, Operand(isolate()->factory()->ToBoolean(done)));
|
||||
__ Mov(empty_fixed_array, Operand(isolate()->factory()->empty_fixed_array()));
|
||||
__ LoadRoot(boolean_done,
|
||||
done ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex);
|
||||
__ LoadRoot(empty_fixed_array, Heap::kEmptyFixedArrayRootIndex);
|
||||
STATIC_ASSERT(JSObject::kPropertiesOffset + kPointerSize ==
|
||||
JSObject::kElementsOffset);
|
||||
STATIC_ASSERT(JSGeneratorObject::kResultValuePropertyOffset + kPointerSize ==
|
||||
JSGeneratorObject::kResultDonePropertyOffset);
|
||||
STATIC_ASSERT(JSIteratorResult::kValueOffset + kPointerSize ==
|
||||
JSIteratorResult::kDoneOffset);
|
||||
__ ObjectUntag(untagged_result, result);
|
||||
__ Str(map_reg, MemOperand(untagged_result, HeapObject::kMapOffset));
|
||||
__ Stp(empty_fixed_array, empty_fixed_array,
|
||||
MemOperand(untagged_result, JSObject::kPropertiesOffset));
|
||||
__ Stp(result_value, boolean_done,
|
||||
MemOperand(untagged_result,
|
||||
JSGeneratorObject::kResultValuePropertyOffset));
|
||||
|
||||
// Only the value field needs a write barrier, as the other values are in the
|
||||
// root set.
|
||||
__ RecordWriteField(result, JSGeneratorObject::kResultValuePropertyOffset,
|
||||
x10, x11, kLRHasBeenSaved, kDontSaveFPRegs);
|
||||
MemOperand(untagged_result, JSIteratorResult::kValueOffset));
|
||||
STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
|
||||
}
|
||||
|
||||
|
||||
|
@ -530,7 +530,8 @@ class FullCodeGenerator: public AstVisitor {
|
||||
F(ToString) \
|
||||
F(ToName) \
|
||||
F(ToObject) \
|
||||
F(DebugIsActive)
|
||||
F(DebugIsActive) \
|
||||
F(CreateIterResultObject)
|
||||
|
||||
#define GENERATOR_DECLARATION(Name) void Emit##Name(CallRuntime* call);
|
||||
FOR_EACH_FULL_CODE_INTRINSIC(GENERATOR_DECLARATION)
|
||||
|
@ -2193,40 +2193,28 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
|
||||
Label gc_required;
|
||||
Label allocated;
|
||||
Label allocate, done_allocate;
|
||||
|
||||
const int instance_size = 5 * kPointerSize;
|
||||
DCHECK_EQ(isolate()->native_context()->iterator_result_map()->instance_size(),
|
||||
instance_size);
|
||||
__ Allocate(JSIteratorResult::kSize, eax, ecx, edx, &allocate, TAG_OBJECT);
|
||||
__ jmp(&done_allocate, Label::kNear);
|
||||
|
||||
__ Allocate(instance_size, eax, ecx, edx, &gc_required, TAG_OBJECT);
|
||||
__ jmp(&allocated);
|
||||
|
||||
__ bind(&gc_required);
|
||||
__ Push(Smi::FromInt(instance_size));
|
||||
__ bind(&allocate);
|
||||
__ Push(Smi::FromInt(JSIteratorResult::kSize));
|
||||
__ CallRuntime(Runtime::kAllocateInNewSpace, 1);
|
||||
__ mov(context_register(),
|
||||
Operand(ebp, StandardFrameConstants::kContextOffset));
|
||||
|
||||
__ bind(&allocated);
|
||||
__ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
|
||||
__ bind(&done_allocate);
|
||||
__ mov(ebx, GlobalObjectOperand());
|
||||
__ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
|
||||
__ mov(ebx, ContextOperand(ebx, Context::ITERATOR_RESULT_MAP_INDEX));
|
||||
__ pop(ecx);
|
||||
__ mov(edx, isolate()->factory()->ToBoolean(done));
|
||||
__ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx);
|
||||
__ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
|
||||
isolate()->factory()->empty_fixed_array());
|
||||
__ mov(FieldOperand(eax, JSObject::kElementsOffset),
|
||||
isolate()->factory()->empty_fixed_array());
|
||||
__ mov(FieldOperand(eax, JSGeneratorObject::kResultValuePropertyOffset), ecx);
|
||||
__ mov(FieldOperand(eax, JSGeneratorObject::kResultDonePropertyOffset), edx);
|
||||
|
||||
// Only the value field needs a write barrier, as the other values are in the
|
||||
// root set.
|
||||
__ RecordWriteField(eax, JSGeneratorObject::kResultValuePropertyOffset,
|
||||
ecx, edx, kDontSaveFPRegs);
|
||||
__ pop(FieldOperand(eax, JSIteratorResult::kValueOffset));
|
||||
__ mov(FieldOperand(eax, JSIteratorResult::kDoneOffset),
|
||||
isolate()->factory()->ToBoolean(done));
|
||||
STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
|
||||
}
|
||||
|
||||
|
||||
@ -4412,6 +4400,36 @@ void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitCreateIterResultObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK_EQ(2, args->length());
|
||||
VisitForStackValue(args->at(0));
|
||||
VisitForStackValue(args->at(1));
|
||||
|
||||
Label runtime, done;
|
||||
|
||||
__ Allocate(JSIteratorResult::kSize, eax, ecx, edx, &runtime, TAG_OBJECT);
|
||||
__ mov(ebx, GlobalObjectOperand());
|
||||
__ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
|
||||
__ mov(ebx, ContextOperand(ebx, Context::ITERATOR_RESULT_MAP_INDEX));
|
||||
__ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx);
|
||||
__ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
|
||||
isolate()->factory()->empty_fixed_array());
|
||||
__ mov(FieldOperand(eax, JSObject::kElementsOffset),
|
||||
isolate()->factory()->empty_fixed_array());
|
||||
__ pop(FieldOperand(eax, JSIteratorResult::kDoneOffset));
|
||||
__ pop(FieldOperand(eax, JSIteratorResult::kValueOffset));
|
||||
STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
|
||||
__ jmp(&done, Label::kNear);
|
||||
|
||||
__ bind(&runtime);
|
||||
__ CallRuntime(Runtime::kCreateIterResultObject, 2);
|
||||
|
||||
__ bind(&done);
|
||||
context()->Plug(eax);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) {
|
||||
// Push undefined as receiver.
|
||||
__ push(Immediate(isolate()->factory()->undefined_value()));
|
||||
|
@ -2266,23 +2266,16 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
|
||||
Label gc_required;
|
||||
Label allocated;
|
||||
Label allocate, done_allocate;
|
||||
|
||||
const int instance_size = 5 * kPointerSize;
|
||||
DCHECK_EQ(isolate()->native_context()->iterator_result_map()->instance_size(),
|
||||
instance_size);
|
||||
__ Allocate(JSIteratorResult::kSize, v0, a2, a3, &allocate, TAG_OBJECT);
|
||||
__ jmp(&done_allocate);
|
||||
|
||||
__ Allocate(instance_size, v0, a2, a3, &gc_required, TAG_OBJECT);
|
||||
__ jmp(&allocated);
|
||||
|
||||
__ bind(&gc_required);
|
||||
__ Push(Smi::FromInt(instance_size));
|
||||
__ bind(&allocate);
|
||||
__ Push(Smi::FromInt(JSIteratorResult::kSize));
|
||||
__ CallRuntime(Runtime::kAllocateInNewSpace, 1);
|
||||
__ lw(context_register(),
|
||||
MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||
|
||||
__ bind(&allocated);
|
||||
__ bind(&done_allocate);
|
||||
__ lw(a1, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ lw(a1, FieldMemOperand(a1, GlobalObject::kNativeContextOffset));
|
||||
__ lw(a1, ContextOperand(a1, Context::ITERATOR_RESULT_MAP_INDEX));
|
||||
@ -2292,15 +2285,9 @@ void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
|
||||
__ sw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
|
||||
__ sw(t0, FieldMemOperand(v0, JSObject::kPropertiesOffset));
|
||||
__ sw(t0, FieldMemOperand(v0, JSObject::kElementsOffset));
|
||||
__ sw(a2,
|
||||
FieldMemOperand(v0, JSGeneratorObject::kResultValuePropertyOffset));
|
||||
__ sw(a3,
|
||||
FieldMemOperand(v0, JSGeneratorObject::kResultDonePropertyOffset));
|
||||
|
||||
// Only the value field needs a write barrier, as the other values are in the
|
||||
// root set.
|
||||
__ RecordWriteField(v0, JSGeneratorObject::kResultValuePropertyOffset,
|
||||
a2, a3, kRAHasBeenSaved, kDontSaveFPRegs);
|
||||
__ sw(a2, FieldMemOperand(v0, JSIteratorResult::kValueOffset));
|
||||
__ sw(a3, FieldMemOperand(v0, JSIteratorResult::kDoneOffset));
|
||||
STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
|
||||
}
|
||||
|
||||
|
||||
@ -4499,6 +4486,37 @@ void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitCreateIterResultObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK_EQ(2, args->length());
|
||||
VisitForStackValue(args->at(0));
|
||||
VisitForStackValue(args->at(1));
|
||||
|
||||
Label runtime, done;
|
||||
|
||||
__ Allocate(JSIteratorResult::kSize, v0, a2, a3, &runtime, TAG_OBJECT);
|
||||
__ lw(a1, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ lw(a1, FieldMemOperand(a1, GlobalObject::kNativeContextOffset));
|
||||
__ lw(a1, ContextOperand(a1, Context::ITERATOR_RESULT_MAP_INDEX));
|
||||
__ pop(a3);
|
||||
__ pop(a2);
|
||||
__ li(t0, Operand(isolate()->factory()->empty_fixed_array()));
|
||||
__ sw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
|
||||
__ sw(t0, FieldMemOperand(v0, JSObject::kPropertiesOffset));
|
||||
__ sw(t0, FieldMemOperand(v0, JSObject::kElementsOffset));
|
||||
__ sw(a2, FieldMemOperand(v0, JSIteratorResult::kValueOffset));
|
||||
__ sw(a3, FieldMemOperand(v0, JSIteratorResult::kDoneOffset));
|
||||
STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
|
||||
__ jmp(&done);
|
||||
|
||||
__ bind(&runtime);
|
||||
__ CallRuntime(Runtime::kCreateIterResultObject, 2);
|
||||
|
||||
__ bind(&done);
|
||||
context()->Plug(v0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) {
|
||||
// Push undefined as the receiver.
|
||||
__ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
|
||||
|
@ -2264,41 +2264,28 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
|
||||
Label gc_required;
|
||||
Label allocated;
|
||||
Label allocate, done_allocate;
|
||||
|
||||
const int instance_size = 5 * kPointerSize;
|
||||
DCHECK_EQ(isolate()->native_context()->iterator_result_map()->instance_size(),
|
||||
instance_size);
|
||||
__ Allocate(JSIteratorResult::kSize, v0, a2, a3, &allocate, TAG_OBJECT);
|
||||
__ jmp(&done_allocate);
|
||||
|
||||
__ Allocate(instance_size, v0, a2, a3, &gc_required, TAG_OBJECT);
|
||||
__ jmp(&allocated);
|
||||
|
||||
__ bind(&gc_required);
|
||||
__ Push(Smi::FromInt(instance_size));
|
||||
__ bind(&allocate);
|
||||
__ Push(Smi::FromInt(JSIteratorResult::kSize));
|
||||
__ CallRuntime(Runtime::kAllocateInNewSpace, 1);
|
||||
__ ld(context_register(),
|
||||
MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||
|
||||
__ bind(&allocated);
|
||||
__ bind(&done_allocate);
|
||||
__ ld(a1, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ ld(a1, FieldMemOperand(a1, GlobalObject::kNativeContextOffset));
|
||||
__ ld(a1, ContextOperand(a1, Context::ITERATOR_RESULT_MAP_INDEX));
|
||||
__ pop(a2);
|
||||
__ li(a3, Operand(isolate()->factory()->ToBoolean(done)));
|
||||
__ li(a4, Operand(isolate()->factory()->empty_fixed_array()));
|
||||
__ li(t0, Operand(isolate()->factory()->empty_fixed_array()));
|
||||
__ sd(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
|
||||
__ sd(a4, FieldMemOperand(v0, JSObject::kPropertiesOffset));
|
||||
__ sd(a4, FieldMemOperand(v0, JSObject::kElementsOffset));
|
||||
__ sd(a2,
|
||||
FieldMemOperand(v0, JSGeneratorObject::kResultValuePropertyOffset));
|
||||
__ sd(a3,
|
||||
FieldMemOperand(v0, JSGeneratorObject::kResultDonePropertyOffset));
|
||||
|
||||
// Only the value field needs a write barrier, as the other values are in the
|
||||
// root set.
|
||||
__ RecordWriteField(v0, JSGeneratorObject::kResultValuePropertyOffset,
|
||||
a2, a3, kRAHasBeenSaved, kDontSaveFPRegs);
|
||||
__ sd(t0, FieldMemOperand(v0, JSObject::kPropertiesOffset));
|
||||
__ sd(t0, FieldMemOperand(v0, JSObject::kElementsOffset));
|
||||
__ sd(a2, FieldMemOperand(v0, JSIteratorResult::kValueOffset));
|
||||
__ sd(a3, FieldMemOperand(v0, JSIteratorResult::kDoneOffset));
|
||||
STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
|
||||
}
|
||||
|
||||
|
||||
@ -4503,6 +4490,37 @@ void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitCreateIterResultObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK_EQ(2, args->length());
|
||||
VisitForStackValue(args->at(0));
|
||||
VisitForStackValue(args->at(1));
|
||||
|
||||
Label runtime, done;
|
||||
|
||||
__ Allocate(JSIteratorResult::kSize, v0, a2, a3, &runtime, TAG_OBJECT);
|
||||
__ ld(a1, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ ld(a1, FieldMemOperand(a1, GlobalObject::kNativeContextOffset));
|
||||
__ ld(a1, ContextOperand(a1, Context::ITERATOR_RESULT_MAP_INDEX));
|
||||
__ pop(a3);
|
||||
__ pop(a2);
|
||||
__ li(t0, Operand(isolate()->factory()->empty_fixed_array()));
|
||||
__ sd(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
|
||||
__ sd(t0, FieldMemOperand(v0, JSObject::kPropertiesOffset));
|
||||
__ sd(t0, FieldMemOperand(v0, JSObject::kElementsOffset));
|
||||
__ sd(a2, FieldMemOperand(v0, JSIteratorResult::kValueOffset));
|
||||
__ sd(a3, FieldMemOperand(v0, JSIteratorResult::kDoneOffset));
|
||||
STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
|
||||
__ jmp(&done);
|
||||
|
||||
__ bind(&runtime);
|
||||
__ CallRuntime(Runtime::kCreateIterResultObject, 2);
|
||||
|
||||
__ bind(&done);
|
||||
context()->Plug(v0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) {
|
||||
// Push undefined as the receiver.
|
||||
__ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
|
||||
|
@ -2217,42 +2217,27 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
|
||||
Label gc_required;
|
||||
Label allocated;
|
||||
Label allocate, done_allocate;
|
||||
|
||||
const int instance_size = 5 * kPointerSize;
|
||||
DCHECK_EQ(isolate()->native_context()->iterator_result_map()->instance_size(),
|
||||
instance_size);
|
||||
__ Allocate(JSIteratorResult::kSize, rax, rcx, rdx, &allocate, TAG_OBJECT);
|
||||
__ jmp(&done_allocate, Label::kNear);
|
||||
|
||||
__ Allocate(instance_size, rax, rcx, rdx, &gc_required, TAG_OBJECT);
|
||||
__ jmp(&allocated);
|
||||
|
||||
__ bind(&gc_required);
|
||||
__ Push(Smi::FromInt(instance_size));
|
||||
__ bind(&allocate);
|
||||
__ Push(Smi::FromInt(JSIteratorResult::kSize));
|
||||
__ CallRuntime(Runtime::kAllocateInNewSpace, 1);
|
||||
__ movp(context_register(),
|
||||
Operand(rbp, StandardFrameConstants::kContextOffset));
|
||||
|
||||
__ bind(&allocated);
|
||||
__ movp(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
|
||||
__ bind(&done_allocate);
|
||||
__ movp(rbx, GlobalObjectOperand());
|
||||
__ movp(rbx, FieldOperand(rbx, GlobalObject::kNativeContextOffset));
|
||||
__ movp(rbx, ContextOperand(rbx, Context::ITERATOR_RESULT_MAP_INDEX));
|
||||
__ Pop(rcx);
|
||||
__ Move(rdx, isolate()->factory()->ToBoolean(done));
|
||||
__ movp(FieldOperand(rax, HeapObject::kMapOffset), rbx);
|
||||
__ Move(FieldOperand(rax, JSObject::kPropertiesOffset),
|
||||
isolate()->factory()->empty_fixed_array());
|
||||
__ Move(FieldOperand(rax, JSObject::kElementsOffset),
|
||||
isolate()->factory()->empty_fixed_array());
|
||||
__ movp(FieldOperand(rax, JSGeneratorObject::kResultValuePropertyOffset),
|
||||
rcx);
|
||||
__ movp(FieldOperand(rax, JSGeneratorObject::kResultDonePropertyOffset),
|
||||
rdx);
|
||||
|
||||
// Only the value field needs a write barrier, as the other values are in the
|
||||
// root set.
|
||||
__ RecordWriteField(rax, JSGeneratorObject::kResultValuePropertyOffset,
|
||||
rcx, rdx, kDontSaveFPRegs);
|
||||
__ LoadRoot(rbx, Heap::kEmptyFixedArrayRootIndex);
|
||||
__ movp(FieldOperand(rax, JSObject::kPropertiesOffset), rbx);
|
||||
__ movp(FieldOperand(rax, JSObject::kElementsOffset), rbx);
|
||||
__ Pop(FieldOperand(rax, JSIteratorResult::kValueOffset));
|
||||
__ LoadRoot(FieldOperand(rax, JSIteratorResult::kDoneOffset),
|
||||
done ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex);
|
||||
STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
|
||||
}
|
||||
|
||||
|
||||
@ -4423,6 +4408,35 @@ void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitCreateIterResultObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK_EQ(2, args->length());
|
||||
VisitForStackValue(args->at(0));
|
||||
VisitForStackValue(args->at(1));
|
||||
|
||||
Label runtime, done;
|
||||
|
||||
__ Allocate(JSIteratorResult::kSize, rax, rcx, rdx, &runtime, TAG_OBJECT);
|
||||
__ movp(rbx, GlobalObjectOperand());
|
||||
__ movp(rbx, FieldOperand(rbx, GlobalObject::kNativeContextOffset));
|
||||
__ movp(rbx, ContextOperand(rbx, Context::ITERATOR_RESULT_MAP_INDEX));
|
||||
__ movp(FieldOperand(rax, HeapObject::kMapOffset), rbx);
|
||||
__ LoadRoot(rbx, Heap::kEmptyFixedArrayRootIndex);
|
||||
__ movp(FieldOperand(rax, JSObject::kPropertiesOffset), rbx);
|
||||
__ movp(FieldOperand(rax, JSObject::kElementsOffset), rbx);
|
||||
__ Pop(FieldOperand(rax, JSIteratorResult::kDoneOffset));
|
||||
__ Pop(FieldOperand(rax, JSIteratorResult::kValueOffset));
|
||||
STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
|
||||
__ jmp(&done, Label::kNear);
|
||||
|
||||
__ bind(&runtime);
|
||||
__ CallRuntime(Runtime::kCreateIterResultObject, 2);
|
||||
|
||||
__ bind(&done);
|
||||
context()->Plug(rax);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) {
|
||||
// Push the builtins object as receiver.
|
||||
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||
|
@ -137,6 +137,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
|
||||
case JS_MESSAGE_OBJECT_TYPE:
|
||||
case JS_SET_ITERATOR_TYPE:
|
||||
case JS_MAP_ITERATOR_TYPE:
|
||||
case JS_ITERATOR_RESULT_TYPE:
|
||||
return GetVisitorIdForSize(kVisitJSObject, kVisitJSObjectGeneric,
|
||||
instance_size, has_unboxed_fields);
|
||||
|
||||
@ -226,6 +227,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
|
||||
case JS_MAP_TYPE:
|
||||
case JS_SET_ITERATOR_TYPE:
|
||||
case JS_MAP_ITERATOR_TYPE:
|
||||
case JS_ITERATOR_RESULT_TYPE:
|
||||
case JS_WEAK_MAP_TYPE:
|
||||
case JS_WEAK_SET_TYPE:
|
||||
case JS_REGEXP_TYPE:
|
||||
|
@ -1816,6 +1816,37 @@ HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(
|
||||
}
|
||||
|
||||
|
||||
HValue* HGraphBuilder::BuildCreateIterResultObject(HValue* value,
|
||||
HValue* done) {
|
||||
NoObservableSideEffectsScope scope(this);
|
||||
|
||||
// Allocate the JSIteratorResult object.
|
||||
HValue* result =
|
||||
Add<HAllocate>(Add<HConstant>(JSIteratorResult::kSize), HType::JSObject(),
|
||||
NOT_TENURED, JS_ITERATOR_RESULT_TYPE);
|
||||
|
||||
// Initialize the JSIteratorResult object.
|
||||
HValue* native_context = BuildGetNativeContext();
|
||||
HValue* map = Add<HLoadNamedField>(
|
||||
native_context, nullptr,
|
||||
HObjectAccess::ForContextSlot(Context::ITERATOR_RESULT_MAP_INDEX));
|
||||
Add<HStoreNamedField>(result, HObjectAccess::ForMap(), map);
|
||||
HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex);
|
||||
Add<HStoreNamedField>(result, HObjectAccess::ForPropertiesPointer(),
|
||||
empty_fixed_array);
|
||||
Add<HStoreNamedField>(result, HObjectAccess::ForElementsPointer(),
|
||||
empty_fixed_array);
|
||||
Add<HStoreNamedField>(result, HObjectAccess::ForObservableJSObjectOffset(
|
||||
JSIteratorResult::kValueOffset),
|
||||
value);
|
||||
Add<HStoreNamedField>(result, HObjectAccess::ForObservableJSObjectOffset(
|
||||
JSIteratorResult::kDoneOffset),
|
||||
done);
|
||||
STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
HValue* HGraphBuilder::BuildRegExpConstructResult(HValue* length,
|
||||
HValue* index,
|
||||
HValue* input) {
|
||||
@ -12597,6 +12628,17 @@ void HOptimizedGraphBuilder::GenerateTheHole(CallRuntime* call) {
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::GenerateCreateIterResultObject(CallRuntime* call) {
|
||||
DCHECK_EQ(2, call->arguments()->length());
|
||||
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
||||
CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
|
||||
HValue* done = Pop();
|
||||
HValue* value = Pop();
|
||||
HValue* result = BuildCreateIterResultObject(value, done);
|
||||
return ast_context()->ReturnValue(result);
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::GenerateJSCollectionGetTable(CallRuntime* call) {
|
||||
DCHECK(call->arguments()->length() == 1);
|
||||
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
||||
|
@ -1358,6 +1358,9 @@ class HGraphBuilder {
|
||||
HValue* hash,
|
||||
LanguageMode language_mode);
|
||||
|
||||
// ES6 section 7.4.7 CreateIterResultObject ( value, done )
|
||||
HValue* BuildCreateIterResultObject(HValue* value, HValue* done);
|
||||
|
||||
HValue* BuildRegExpConstructResult(HValue* length,
|
||||
HValue* index,
|
||||
HValue* input);
|
||||
@ -2267,6 +2270,8 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
F(JSCollectionGetTable) \
|
||||
F(StringGetRawHashField) \
|
||||
F(TheHole) \
|
||||
/* ES6 Iterators */ \
|
||||
F(CreateIterResultObject) \
|
||||
/* Arrays */ \
|
||||
F(HasFastPackedElements) \
|
||||
/* Strings */ \
|
||||
|
@ -144,6 +144,9 @@ void HeapObject::HeapObjectVerify() {
|
||||
case JS_MAP_ITERATOR_TYPE:
|
||||
JSMapIterator::cast(this)->JSMapIteratorVerify();
|
||||
break;
|
||||
case JS_ITERATOR_RESULT_TYPE:
|
||||
JSIteratorResult::cast(this)->JSIteratorResultVerify();
|
||||
break;
|
||||
case JS_WEAK_MAP_TYPE:
|
||||
JSWeakMap::cast(this)->JSWeakMapVerify();
|
||||
break;
|
||||
@ -741,6 +744,14 @@ void JSMapIterator::JSMapIteratorVerify() {
|
||||
}
|
||||
|
||||
|
||||
void JSIteratorResult::JSIteratorResultVerify() {
|
||||
CHECK(IsJSIteratorResult());
|
||||
JSObjectVerify();
|
||||
VerifyPointer(done());
|
||||
VerifyPointer(value());
|
||||
}
|
||||
|
||||
|
||||
void JSWeakMap::JSWeakMapVerify() {
|
||||
CHECK(IsJSWeakMap());
|
||||
JSObjectVerify();
|
||||
|
@ -704,6 +704,7 @@ TYPE_CHECKER(JSSet, JS_SET_TYPE)
|
||||
TYPE_CHECKER(JSMap, JS_MAP_TYPE)
|
||||
TYPE_CHECKER(JSSetIterator, JS_SET_ITERATOR_TYPE)
|
||||
TYPE_CHECKER(JSMapIterator, JS_MAP_ITERATOR_TYPE)
|
||||
TYPE_CHECKER(JSIteratorResult, JS_ITERATOR_RESULT_TYPE)
|
||||
TYPE_CHECKER(JSWeakMap, JS_WEAK_MAP_TYPE)
|
||||
TYPE_CHECKER(JSWeakSet, JS_WEAK_SET_TYPE)
|
||||
TYPE_CHECKER(JSContextExtensionObject, JS_CONTEXT_EXTENSION_OBJECT_TYPE)
|
||||
@ -2150,6 +2151,8 @@ int JSObject::GetHeaderSize() {
|
||||
return JSSetIterator::kSize;
|
||||
case JS_MAP_ITERATOR_TYPE:
|
||||
return JSMapIterator::kSize;
|
||||
case JS_ITERATOR_RESULT_TYPE:
|
||||
return JSIteratorResult::kSize;
|
||||
case JS_WEAK_MAP_TYPE:
|
||||
return JSWeakMap::kSize;
|
||||
case JS_WEAK_SET_TYPE:
|
||||
@ -3325,6 +3328,7 @@ CAST_ACCESSOR(JSReceiver)
|
||||
CAST_ACCESSOR(JSRegExp)
|
||||
CAST_ACCESSOR(JSSet)
|
||||
CAST_ACCESSOR(JSSetIterator)
|
||||
CAST_ACCESSOR(JSIteratorResult)
|
||||
CAST_ACCESSOR(JSTypedArray)
|
||||
CAST_ACCESSOR(JSValue)
|
||||
CAST_ACCESSOR(JSWeakMap)
|
||||
@ -7799,6 +7803,10 @@ Object* JSMapIterator::CurrentValue() {
|
||||
}
|
||||
|
||||
|
||||
ACCESSORS(JSIteratorResult, done, Object, kDoneOffset)
|
||||
ACCESSORS(JSIteratorResult, value, Object, kValueOffset)
|
||||
|
||||
|
||||
String::SubStringRange::SubStringRange(String* string, int first, int length)
|
||||
: string_(string),
|
||||
first_(first),
|
||||
|
@ -144,6 +144,9 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
|
||||
case JS_MAP_ITERATOR_TYPE:
|
||||
JSMapIterator::cast(this)->JSMapIteratorPrint(os);
|
||||
break;
|
||||
case JS_ITERATOR_RESULT_TYPE:
|
||||
JSIteratorResult::cast(this)->JSIteratorResultPrint(os);
|
||||
break;
|
||||
case JS_WEAK_MAP_TYPE:
|
||||
JSWeakMap::cast(this)->JSWeakMapPrint(os);
|
||||
break;
|
||||
@ -756,6 +759,15 @@ void JSMapIterator::JSMapIteratorPrint(std::ostream& os) { // NOLINT
|
||||
}
|
||||
|
||||
|
||||
void JSIteratorResult::JSIteratorResultPrint(std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "JSIteratorResult");
|
||||
os << " - map = " << reinterpret_cast<void*>(map()) << "\n";
|
||||
os << " - done = " << Brief(done()) << "\n";
|
||||
os << " - value = " << Brief(value()) << "\n";
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
|
||||
void JSWeakMap::JSWeakMapPrint(std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "JSWeakMap");
|
||||
os << " - map = " << reinterpret_cast<void*>(map()) << "\n";
|
||||
|
@ -431,6 +431,7 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
|
||||
V(JS_MAP_TYPE) \
|
||||
V(JS_SET_ITERATOR_TYPE) \
|
||||
V(JS_MAP_ITERATOR_TYPE) \
|
||||
V(JS_ITERATOR_RESULT_TYPE) \
|
||||
V(JS_WEAK_MAP_TYPE) \
|
||||
V(JS_WEAK_SET_TYPE) \
|
||||
V(JS_REGEXP_TYPE) \
|
||||
@ -729,6 +730,7 @@ enum InstanceType {
|
||||
JS_MAP_TYPE,
|
||||
JS_SET_ITERATOR_TYPE,
|
||||
JS_MAP_ITERATOR_TYPE,
|
||||
JS_ITERATOR_RESULT_TYPE,
|
||||
JS_WEAK_MAP_TYPE,
|
||||
JS_WEAK_SET_TYPE,
|
||||
JS_REGEXP_TYPE,
|
||||
@ -957,6 +959,7 @@ template <class C> inline bool Is(Object* obj);
|
||||
V(JSMap) \
|
||||
V(JSSetIterator) \
|
||||
V(JSMapIterator) \
|
||||
V(JSIteratorResult) \
|
||||
V(JSWeakCollection) \
|
||||
V(JSWeakMap) \
|
||||
V(JSWeakSet) \
|
||||
@ -6860,17 +6863,6 @@ class JSGeneratorObject: public JSObject {
|
||||
// Resume mode, for use by runtime functions.
|
||||
enum ResumeMode { NEXT, THROW };
|
||||
|
||||
// Yielding from a generator returns an object with the following inobject
|
||||
// properties. See Context::iterator_result_map() for the map.
|
||||
static const int kResultValuePropertyIndex = 0;
|
||||
static const int kResultDonePropertyIndex = 1;
|
||||
static const int kResultPropertyCount = 2;
|
||||
|
||||
static const int kResultValuePropertyOffset = JSObject::kHeaderSize;
|
||||
static const int kResultDonePropertyOffset =
|
||||
kResultValuePropertyOffset + kPointerSize;
|
||||
static const int kResultSize = kResultDonePropertyOffset + kPointerSize;
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(JSGeneratorObject);
|
||||
};
|
||||
@ -9489,6 +9481,40 @@ class JSMapIterator: public OrderedHashTableIterator<JSMapIterator,
|
||||
};
|
||||
|
||||
|
||||
// ES6 section 25.1.1.3 The IteratorResult Interface
|
||||
class JSIteratorResult final : public JSObject {
|
||||
public:
|
||||
// [done]: This is the result status of an iterator next method call. If the
|
||||
// end of the iterator was reached done is true. If the end was not reached
|
||||
// done is false and a [value] is available.
|
||||
DECL_ACCESSORS(done, Object)
|
||||
|
||||
// [value]: If [done] is false, this is the current iteration element value.
|
||||
// If [done] is true, this is the return value of the iterator, if it supplied
|
||||
// one. If the iterator does not have a return value, value is undefined.
|
||||
// In that case, the value property may be absent from the conforming object
|
||||
// if it does not inherit an explicit value property.
|
||||
DECL_ACCESSORS(value, Object)
|
||||
|
||||
// Dispatched behavior.
|
||||
DECLARE_PRINTER(JSIteratorResult)
|
||||
DECLARE_VERIFIER(JSIteratorResult)
|
||||
|
||||
DECLARE_CAST(JSIteratorResult)
|
||||
|
||||
static const int kValueOffset = JSObject::kHeaderSize;
|
||||
static const int kDoneOffset = kValueOffset + kPointerSize;
|
||||
static const int kSize = kDoneOffset + kPointerSize;
|
||||
|
||||
// Indices of in-object properties.
|
||||
static const int kValueIndex = 0;
|
||||
static const int kDoneIndex = 1;
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(JSIteratorResult);
|
||||
};
|
||||
|
||||
|
||||
// Base class for both JSWeakMap and JSWeakSet
|
||||
class JSWeakCollection: public JSObject {
|
||||
public:
|
||||
|
@ -1558,5 +1558,15 @@ RUNTIME_FUNCTION(Runtime_HasInPrototypeChain) {
|
||||
object->HasInPrototypeChain(isolate, prototype));
|
||||
}
|
||||
|
||||
|
||||
// ES6 section 7.4.7 CreateIterResultObject ( value, done )
|
||||
RUNTIME_FUNCTION(Runtime_CreateIterResultObject) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(2, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, done, 1);
|
||||
return *isolate->factory()->NewJSIteratorResult(value, done);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -498,7 +498,8 @@ namespace internal {
|
||||
F(ToName, 1, 1) \
|
||||
F(StrictEquals, 2, 1) \
|
||||
F(InstanceOf, 2, 1) \
|
||||
F(HasInPrototypeChain, 2, 1)
|
||||
F(HasInPrototypeChain, 2, 1) \
|
||||
F(CreateIterResultObject, 2, 1)
|
||||
|
||||
|
||||
#define FOR_EACH_INTRINSIC_OBSERVE(F) \
|
||||
|
@ -11,7 +11,6 @@
|
||||
// -------------------------------------------------------------------
|
||||
// Imports
|
||||
|
||||
var ArrayIteratorCreateResultObject;
|
||||
var GlobalString = global.String;
|
||||
var iteratorSymbol = utils.ImportNow("iterator_symbol");
|
||||
var stringIteratorIteratedStringSymbol =
|
||||
@ -20,10 +19,6 @@ var stringIteratorNextIndexSymbol =
|
||||
utils.ImportNow("string_iterator_next_index_symbol");
|
||||
var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
|
||||
|
||||
utils.Import(function(from) {
|
||||
ArrayIteratorCreateResultObject = from.ArrayIteratorCreateResultObject;
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
function StringIterator() {}
|
||||
@ -39,9 +34,11 @@ function CreateStringIterator(string) {
|
||||
}
|
||||
|
||||
|
||||
// 21.1.5.2.1 %StringIteratorPrototype%.next( )
|
||||
// ES6 section 21.1.5.2.1 %StringIteratorPrototype%.next ( )
|
||||
function StringIteratorNext() {
|
||||
var iterator = this;
|
||||
var value = UNDEFINED;
|
||||
var done = true;
|
||||
|
||||
if (!IS_SPEC_OBJECT(iterator) ||
|
||||
!HAS_DEFINED_PRIVATE(iterator, stringIteratorNextIndexSymbol)) {
|
||||
@ -50,34 +47,29 @@ function StringIteratorNext() {
|
||||
}
|
||||
|
||||
var s = GET_PRIVATE(iterator, stringIteratorIteratedStringSymbol);
|
||||
if (IS_UNDEFINED(s)) {
|
||||
return ArrayIteratorCreateResultObject(UNDEFINED, true);
|
||||
}
|
||||
|
||||
var position = GET_PRIVATE(iterator, stringIteratorNextIndexSymbol);
|
||||
var length = TO_UINT32(s.length);
|
||||
|
||||
if (position >= length) {
|
||||
SET_PRIVATE(iterator, stringIteratorIteratedStringSymbol,
|
||||
UNDEFINED);
|
||||
return ArrayIteratorCreateResultObject(UNDEFINED, true);
|
||||
}
|
||||
|
||||
var first = %_StringCharCodeAt(s, position);
|
||||
var resultString = %_StringCharFromCode(first);
|
||||
position++;
|
||||
|
||||
if (first >= 0xD800 && first <= 0xDBFF && position < length) {
|
||||
var second = %_StringCharCodeAt(s, position);
|
||||
if (second >= 0xDC00 && second <= 0xDFFF) {
|
||||
resultString += %_StringCharFromCode(second);
|
||||
if (!IS_UNDEFINED(s)) {
|
||||
var position = GET_PRIVATE(iterator, stringIteratorNextIndexSymbol);
|
||||
var length = TO_UINT32(s.length);
|
||||
if (position >= length) {
|
||||
SET_PRIVATE(iterator, stringIteratorIteratedStringSymbol, UNDEFINED);
|
||||
} else {
|
||||
var first = %_StringCharCodeAt(s, position);
|
||||
value = %_StringCharFromCode(first);
|
||||
done = false;
|
||||
position++;
|
||||
|
||||
if (first >= 0xD800 && first <= 0xDBFF && position < length) {
|
||||
var second = %_StringCharCodeAt(s, position);
|
||||
if (second >= 0xDC00 && second <= 0xDFFF) {
|
||||
value += %_StringCharFromCode(second);
|
||||
position++;
|
||||
}
|
||||
}
|
||||
|
||||
SET_PRIVATE(iterator, stringIteratorNextIndexSymbol, position);
|
||||
}
|
||||
}
|
||||
|
||||
SET_PRIVATE(iterator, stringIteratorNextIndexSymbol, position);
|
||||
|
||||
return ArrayIteratorCreateResultObject(resultString, false);
|
||||
return %_CreateIterResultObject(value, done);
|
||||
}
|
||||
|
||||
|
||||
|
@ -133,6 +133,10 @@ class MacroAssembler: public Assembler {
|
||||
|
||||
// Operations on roots in the root-array.
|
||||
void LoadRoot(Register destination, Heap::RootListIndex index);
|
||||
void LoadRoot(const Operand& destination, Heap::RootListIndex index) {
|
||||
LoadRoot(kScratchRegister, index);
|
||||
movp(destination, kScratchRegister);
|
||||
}
|
||||
void StoreRoot(Register source, Heap::RootListIndex index);
|
||||
// Load a root value where the index (or part of it) is variable.
|
||||
// The variable_offset register is added to the fixed_offset value
|
||||
|
Loading…
Reference in New Issue
Block a user