[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:
bmeurer 2015-09-03 05:16:15 -07:00 committed by Commit bot
parent c8dbd2c477
commit 72bc4b5c8a
24 changed files with 492 additions and 260 deletions

View File

@ -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]);

View File

@ -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

View File

@ -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;
}

View File

@ -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) \

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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)

View File

@ -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()));

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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:

View File

@ -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)));

View File

@ -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 */ \

View File

@ -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();

View File

@ -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),

View File

@ -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";

View File

@ -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:

View File

@ -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

View File

@ -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) \

View File

@ -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);
}

View File

@ -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