|
|
@ -299,24 +299,26 @@ void FullCodeGenerator::Generate() { |
|
|
|
} |
|
|
|
VisitDeclarations(scope()->declarations()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
{ Comment cmnt(masm_, "[ Stack check"); |
|
|
|
PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); |
|
|
|
Label ok; |
|
|
|
DCHECK(jssp.Is(__ StackPointer())); |
|
|
|
__ CompareRoot(jssp, Heap::kStackLimitRootIndex); |
|
|
|
__ B(hs, &ok); |
|
|
|
PredictableCodeSizeScope predictable(masm_, |
|
|
|
Assembler::kCallSizeWithRelocation); |
|
|
|
__ Call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET); |
|
|
|
__ Bind(&ok); |
|
|
|
} |
|
|
|
{ |
|
|
|
Comment cmnt(masm_, "[ Stack check"); |
|
|
|
PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); |
|
|
|
Label ok; |
|
|
|
DCHECK(jssp.Is(__ StackPointer())); |
|
|
|
__ CompareRoot(jssp, Heap::kStackLimitRootIndex); |
|
|
|
__ B(hs, &ok); |
|
|
|
PredictableCodeSizeScope predictable(masm_, |
|
|
|
Assembler::kCallSizeWithRelocation); |
|
|
|
__ Call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET); |
|
|
|
__ Bind(&ok); |
|
|
|
} |
|
|
|
|
|
|
|
{ Comment cmnt(masm_, "[ Body"); |
|
|
|
DCHECK(loop_depth() == 0); |
|
|
|
VisitStatements(function()->body()); |
|
|
|
DCHECK(loop_depth() == 0); |
|
|
|
{ |
|
|
|
Comment cmnt(masm_, "[ Body"); |
|
|
|
DCHECK(loop_depth() == 0); |
|
|
|
VisitStatements(function()->body()); |
|
|
|
DCHECK(loop_depth() == 0); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Always emit a 'return undefined' in case control fell off the end of
|
|
|
@ -1097,7 +1099,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
|
|
|
void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
|
|
|
ASM_LOCATION("FullCodeGenerator::VisitForInStatement"); |
|
|
|
Comment cmnt(masm_, "[ ForInStatement"); |
|
|
|
int slot = stmt->ForInFeedbackSlot(); |
|
|
|
FeedbackVectorSlot slot = stmt->ForInFeedbackSlot(); |
|
|
|
// TODO(all): This visitor probably needs better comments and a revisit.
|
|
|
|
SetStatementPosition(stmt); |
|
|
|
|
|
|
@ -1124,6 +1126,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
|
|
|
__ Push(x0); |
|
|
|
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
|
|
|
__ Bind(&done_convert); |
|
|
|
PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG); |
|
|
|
__ Push(x0); |
|
|
|
|
|
|
|
// Check for proxies.
|
|
|
@ -1147,6 +1150,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
|
|
|
__ Bind(&call_runtime); |
|
|
|
__ Push(x0); // Duplicate the enumerable object on the stack.
|
|
|
|
__ CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
|
|
|
PrepareForBailoutForId(stmt->EnumId(), TOS_REG); |
|
|
|
|
|
|
|
// If we got a map from the runtime call, we can do a fast
|
|
|
|
// modification check. Otherwise, we got a fixed array, and we have
|
|
|
@ -1181,7 +1185,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
|
|
|
|
|
|
|
__ LoadObject(x1, FeedbackVector()); |
|
|
|
__ Mov(x10, Operand(TypeFeedbackVector::MegamorphicSentinel(isolate()))); |
|
|
|
__ Str(x10, FieldMemOperand(x1, FixedArray::OffsetOfElementAt(slot))); |
|
|
|
int vector_index = FeedbackVector()->GetIndex(slot); |
|
|
|
__ Str(x10, FieldMemOperand(x1, FixedArray::OffsetOfElementAt(vector_index))); |
|
|
|
|
|
|
|
__ Mov(x1, Smi::FromInt(1)); // Smi indicates slow check.
|
|
|
|
__ Peek(x10, 0); // Get enumerated object.
|
|
|
@ -1350,7 +1355,13 @@ void FullCodeGenerator::EmitLoadHomeObject(SuperReference* expr) { |
|
|
|
Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol()); |
|
|
|
__ Mov(LoadDescriptor::NameRegister(), Operand(home_object_symbol)); |
|
|
|
|
|
|
|
CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId()); |
|
|
|
if (FLAG_vector_ics) { |
|
|
|
__ Mov(VectorLoadICDescriptor::SlotRegister(), |
|
|
|
SmiFromSlot(expr->HomeObjectFeedbackSlot())); |
|
|
|
CallLoadIC(NOT_CONTEXTUAL); |
|
|
|
} else { |
|
|
|
CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId()); |
|
|
|
} |
|
|
|
|
|
|
|
__ Mov(x10, Operand(isolate()->factory()->undefined_value())); |
|
|
|
__ cmp(x0, x10); |
|
|
@ -1408,7 +1419,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy, |
|
|
|
__ Mov(LoadDescriptor::NameRegister(), Operand(proxy->var()->name())); |
|
|
|
if (FLAG_vector_ics) { |
|
|
|
__ Mov(VectorLoadICDescriptor::SlotRegister(), |
|
|
|
Smi::FromInt(proxy->VariableFeedbackSlot())); |
|
|
|
SmiFromSlot(proxy->VariableFeedbackSlot())); |
|
|
|
} |
|
|
|
|
|
|
|
ContextualMode mode = (typeof_state == INSIDE_TYPEOF) ? NOT_CONTEXTUAL |
|
|
@ -1493,7 +1504,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
|
|
|
__ Mov(LoadDescriptor::NameRegister(), Operand(var->name())); |
|
|
|
if (FLAG_vector_ics) { |
|
|
|
__ Mov(VectorLoadICDescriptor::SlotRegister(), |
|
|
|
Smi::FromInt(proxy->VariableFeedbackSlot())); |
|
|
|
SmiFromSlot(proxy->VariableFeedbackSlot())); |
|
|
|
} |
|
|
|
CallLoadIC(CONTEXTUAL); |
|
|
|
context()->Plug(x0); |
|
|
@ -1671,6 +1682,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
|
|
|
FastCloneShallowObjectStub stub(isolate(), properties_count); |
|
|
|
__ CallStub(&stub); |
|
|
|
} |
|
|
|
PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); |
|
|
|
|
|
|
|
// If result_saved is true the result is on top of the stack. If
|
|
|
|
// result_saved is false the result is in x0.
|
|
|
@ -1699,6 +1711,8 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
|
|
|
DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value())); |
|
|
|
// Fall through.
|
|
|
|
case ObjectLiteral::Property::COMPUTED: |
|
|
|
// It is safe to use [[Put]] here because the boilerplate already
|
|
|
|
// contains computed properties with an uninitialized value.
|
|
|
|
if (key->value()->IsInternalizedString()) { |
|
|
|
if (property->emit_store()) { |
|
|
|
VisitForAccumulatorValue(value); |
|
|
@ -1732,7 +1746,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
|
|
|
__ Peek(x0, 0); |
|
|
|
__ Push(x0); |
|
|
|
VisitForStackValue(value); |
|
|
|
__ CallRuntime(Runtime::kSetPrototype, 2); |
|
|
|
__ CallRuntime(Runtime::kInternalSetPrototype, 2); |
|
|
|
} else { |
|
|
|
VisitForEffect(value); |
|
|
|
} |
|
|
@ -1862,22 +1876,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
|
|
|
|
|
|
|
Comment cmnt(masm_, "[ Assignment"); |
|
|
|
|
|
|
|
// Left-hand side can only be a property, a global or a (parameter or local)
|
|
|
|
// slot.
|
|
|
|
enum LhsKind { |
|
|
|
VARIABLE, |
|
|
|
NAMED_PROPERTY, |
|
|
|
KEYED_PROPERTY, |
|
|
|
NAMED_SUPER_PROPERTY |
|
|
|
}; |
|
|
|
LhsKind assign_type = VARIABLE; |
|
|
|
Property* property = expr->target()->AsProperty(); |
|
|
|
if (property != NULL) { |
|
|
|
assign_type = (property->key()->IsPropertyName()) |
|
|
|
? (property->IsSuperAccess() ? NAMED_SUPER_PROPERTY |
|
|
|
: NAMED_PROPERTY) |
|
|
|
: KEYED_PROPERTY; |
|
|
|
} |
|
|
|
LhsKind assign_type = GetAssignType(property); |
|
|
|
|
|
|
|
// Evaluate LHS expression.
|
|
|
|
switch (assign_type) { |
|
|
@ -1903,6 +1903,20 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
|
|
|
__ Push(scratch, result_register()); |
|
|
|
} |
|
|
|
break; |
|
|
|
case KEYED_SUPER_PROPERTY: |
|
|
|
VisitForStackValue(property->obj()->AsSuperReference()->this_var()); |
|
|
|
EmitLoadHomeObject(property->obj()->AsSuperReference()); |
|
|
|
__ Push(result_register()); |
|
|
|
VisitForAccumulatorValue(property->key()); |
|
|
|
__ Push(result_register()); |
|
|
|
if (expr->is_compound()) { |
|
|
|
const Register scratch1 = x10; |
|
|
|
const Register scratch2 = x11; |
|
|
|
__ Peek(scratch1, 2 * kPointerSize); |
|
|
|
__ Peek(scratch2, kPointerSize); |
|
|
|
__ Push(scratch1, scratch2, result_register()); |
|
|
|
} |
|
|
|
break; |
|
|
|
case KEYED_PROPERTY: |
|
|
|
if (expr->is_compound()) { |
|
|
|
VisitForStackValue(property->obj()); |
|
|
@ -1933,6 +1947,10 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
|
|
|
EmitNamedSuperPropertyLoad(property); |
|
|
|
PrepareForBailoutForId(property->LoadId(), TOS_REG); |
|
|
|
break; |
|
|
|
case KEYED_SUPER_PROPERTY: |
|
|
|
EmitKeyedSuperPropertyLoad(property); |
|
|
|
PrepareForBailoutForId(property->LoadId(), TOS_REG); |
|
|
|
break; |
|
|
|
case KEYED_PROPERTY: |
|
|
|
EmitKeyedPropertyLoad(property); |
|
|
|
PrepareForBailoutForId(property->LoadId(), TOS_REG); |
|
|
@ -1980,7 +1998,12 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
|
|
|
EmitNamedPropertyAssignment(expr); |
|
|
|
break; |
|
|
|
case NAMED_SUPER_PROPERTY: |
|
|
|
EmitNamedSuperPropertyAssignment(expr); |
|
|
|
EmitNamedSuperPropertyStore(property); |
|
|
|
context()->Plug(x0); |
|
|
|
break; |
|
|
|
case KEYED_SUPER_PROPERTY: |
|
|
|
EmitKeyedSuperPropertyStore(property); |
|
|
|
context()->Plug(x0); |
|
|
|
break; |
|
|
|
case KEYED_PROPERTY: |
|
|
|
EmitKeyedPropertyAssignment(expr); |
|
|
@ -1997,7 +2020,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
|
|
|
__ Mov(LoadDescriptor::NameRegister(), Operand(key->value())); |
|
|
|
if (FLAG_vector_ics) { |
|
|
|
__ Mov(VectorLoadICDescriptor::SlotRegister(), |
|
|
|
Smi::FromInt(prop->PropertyFeedbackSlot())); |
|
|
|
SmiFromSlot(prop->PropertyFeedbackSlot())); |
|
|
|
CallLoadIC(NOT_CONTEXTUAL); |
|
|
|
} else { |
|
|
|
CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); |
|
|
@ -2019,11 +2042,11 @@ void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) { |
|
|
|
|
|
|
|
void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
|
|
|
SetSourcePosition(prop->position()); |
|
|
|
// Call keyed load IC. It has arguments key and receiver in r0 and r1.
|
|
|
|
// Call keyed load IC. It has arguments key and receiver in x0 and x1.
|
|
|
|
Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code(); |
|
|
|
if (FLAG_vector_ics) { |
|
|
|
__ Mov(VectorLoadICDescriptor::SlotRegister(), |
|
|
|
Smi::FromInt(prop->PropertyFeedbackSlot())); |
|
|
|
SmiFromSlot(prop->PropertyFeedbackSlot())); |
|
|
|
CallIC(ic); |
|
|
|
} else { |
|
|
|
CallIC(ic, prop->PropertyFeedbackId()); |
|
|
@ -2031,6 +2054,14 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) { |
|
|
|
// Stack: receiver, home_object, key.
|
|
|
|
SetSourcePosition(prop->position()); |
|
|
|
|
|
|
|
__ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, |
|
|
|
Token::Value op, |
|
|
|
OverwriteMode mode, |
|
|
@ -2146,19 +2177,67 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { |
|
|
|
// Constructor is in x0.
|
|
|
|
DCHECK(lit != NULL); |
|
|
|
__ push(x0); |
|
|
|
|
|
|
|
// No access check is needed here since the constructor is created by the
|
|
|
|
// class literal.
|
|
|
|
Register scratch = x1; |
|
|
|
__ Ldr(scratch, |
|
|
|
FieldMemOperand(x0, JSFunction::kPrototypeOrInitialMapOffset)); |
|
|
|
__ Push(scratch); |
|
|
|
|
|
|
|
for (int i = 0; i < lit->properties()->length(); i++) { |
|
|
|
ObjectLiteral::Property* property = lit->properties()->at(i); |
|
|
|
Literal* key = property->key()->AsLiteral(); |
|
|
|
Expression* value = property->value(); |
|
|
|
DCHECK(key != NULL); |
|
|
|
|
|
|
|
if (property->is_static()) { |
|
|
|
__ Peek(scratch, kPointerSize); // constructor
|
|
|
|
} else { |
|
|
|
__ Peek(scratch, 0); // prototype
|
|
|
|
} |
|
|
|
__ Push(scratch); |
|
|
|
VisitForStackValue(key); |
|
|
|
VisitForStackValue(value); |
|
|
|
|
|
|
|
switch (property->kind()) { |
|
|
|
case ObjectLiteral::Property::CONSTANT: |
|
|
|
case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
|
|
|
case ObjectLiteral::Property::COMPUTED: |
|
|
|
case ObjectLiteral::Property::PROTOTYPE: |
|
|
|
__ CallRuntime(Runtime::kDefineClassMethod, 3); |
|
|
|
break; |
|
|
|
|
|
|
|
case ObjectLiteral::Property::GETTER: |
|
|
|
__ CallRuntime(Runtime::kDefineClassGetter, 3); |
|
|
|
break; |
|
|
|
|
|
|
|
case ObjectLiteral::Property::SETTER: |
|
|
|
__ CallRuntime(Runtime::kDefineClassSetter, 3); |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
UNREACHABLE(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// prototype
|
|
|
|
__ CallRuntime(Runtime::kToFastProperties, 1); |
|
|
|
|
|
|
|
// constructor
|
|
|
|
__ CallRuntime(Runtime::kToFastProperties, 1); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void FullCodeGenerator::EmitAssignment(Expression* expr) { |
|
|
|
DCHECK(expr->IsValidReferenceExpression()); |
|
|
|
|
|
|
|
// Left-hand side can only be a property, a global or a (parameter or local)
|
|
|
|
// slot.
|
|
|
|
enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
|
|
|
LhsKind assign_type = VARIABLE; |
|
|
|
Property* prop = expr->AsProperty(); |
|
|
|
if (prop != NULL) { |
|
|
|
assign_type = (prop->key()->IsPropertyName()) |
|
|
|
? NAMED_PROPERTY |
|
|
|
: KEYED_PROPERTY; |
|
|
|
} |
|
|
|
LhsKind assign_type = GetAssignType(prop); |
|
|
|
|
|
|
|
switch (assign_type) { |
|
|
|
case VARIABLE: { |
|
|
@ -2179,6 +2258,42 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) { |
|
|
|
CallStoreIC(); |
|
|
|
break; |
|
|
|
} |
|
|
|
case NAMED_SUPER_PROPERTY: { |
|
|
|
__ Push(x0); |
|
|
|
VisitForStackValue(prop->obj()->AsSuperReference()->this_var()); |
|
|
|
EmitLoadHomeObject(prop->obj()->AsSuperReference()); |
|
|
|
// stack: value, this; x0: home_object
|
|
|
|
Register scratch = x10; |
|
|
|
Register scratch2 = x11; |
|
|
|
__ mov(scratch, result_register()); // home_object
|
|
|
|
__ Peek(x0, kPointerSize); // value
|
|
|
|
__ Peek(scratch2, 0); // this
|
|
|
|
__ Poke(scratch2, kPointerSize); // this
|
|
|
|
__ Poke(scratch, 0); // home_object
|
|
|
|
// stack: this, home_object; x0: value
|
|
|
|
EmitNamedSuperPropertyStore(prop); |
|
|
|
break; |
|
|
|
} |
|
|
|
case KEYED_SUPER_PROPERTY: { |
|
|
|
__ Push(x0); |
|
|
|
VisitForStackValue(prop->obj()->AsSuperReference()->this_var()); |
|
|
|
EmitLoadHomeObject(prop->obj()->AsSuperReference()); |
|
|
|
__ Push(result_register()); |
|
|
|
VisitForAccumulatorValue(prop->key()); |
|
|
|
Register scratch = x10; |
|
|
|
Register scratch2 = x11; |
|
|
|
__ Peek(scratch2, 2 * kPointerSize); // value
|
|
|
|
// stack: value, this, home_object; x0: key, x11: value
|
|
|
|
__ Peek(scratch, kPointerSize); // this
|
|
|
|
__ Poke(scratch, 2 * kPointerSize); |
|
|
|
__ Peek(scratch, 0); // home_object
|
|
|
|
__ Poke(scratch, kPointerSize); |
|
|
|
__ Poke(x0, 0); |
|
|
|
__ Move(x0, scratch2); |
|
|
|
// stack: this, home_object, key; x0: value.
|
|
|
|
EmitKeyedSuperPropertyStore(prop); |
|
|
|
break; |
|
|
|
} |
|
|
|
case KEYED_PROPERTY: { |
|
|
|
__ Push(x0); // Preserve value.
|
|
|
|
VisitForStackValue(prop->obj()); |
|
|
@ -2297,21 +2412,32 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void FullCodeGenerator::EmitNamedSuperPropertyAssignment(Assignment* expr) { |
|
|
|
void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) { |
|
|
|
// Assignment to named property of super.
|
|
|
|
// x0 : value
|
|
|
|
// stack : receiver ('this'), home_object
|
|
|
|
Property* prop = expr->target()->AsProperty(); |
|
|
|
DCHECK(prop != NULL); |
|
|
|
Literal* key = prop->key()->AsLiteral(); |
|
|
|
DCHECK(key != NULL); |
|
|
|
|
|
|
|
__ Push(x0); |
|
|
|
__ Push(key->value()); |
|
|
|
__ Push(x0); |
|
|
|
__ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict |
|
|
|
: Runtime::kStoreToSuper_Sloppy), |
|
|
|
4); |
|
|
|
context()->Plug(x0); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) { |
|
|
|
// Assignment to named property of super.
|
|
|
|
// x0 : value
|
|
|
|
// stack : receiver ('this'), home_object, key
|
|
|
|
DCHECK(prop != NULL); |
|
|
|
|
|
|
|
__ Push(x0); |
|
|
|
__ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreKeyedToSuper_Strict |
|
|
|
: Runtime::kStoreKeyedToSuper_Sloppy), |
|
|
|
4); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -2351,11 +2477,19 @@ void FullCodeGenerator::VisitProperty(Property* expr) { |
|
|
|
PrepareForBailoutForId(expr->LoadId(), TOS_REG); |
|
|
|
context()->Plug(x0); |
|
|
|
} else { |
|
|
|
VisitForStackValue(expr->obj()); |
|
|
|
VisitForAccumulatorValue(expr->key()); |
|
|
|
__ Move(LoadDescriptor::NameRegister(), x0); |
|
|
|
__ Pop(LoadDescriptor::ReceiverRegister()); |
|
|
|
EmitKeyedPropertyLoad(expr); |
|
|
|
if (!expr->IsSuperAccess()) { |
|
|
|
VisitForStackValue(expr->obj()); |
|
|
|
VisitForAccumulatorValue(expr->key()); |
|
|
|
__ Move(LoadDescriptor::NameRegister(), x0); |
|
|
|
__ Pop(LoadDescriptor::ReceiverRegister()); |
|
|
|
EmitKeyedPropertyLoad(expr); |
|
|
|
} else { |
|
|
|
VisitForStackValue(expr->obj()->AsSuperReference()->this_var()); |
|
|
|
EmitLoadHomeObject(expr->obj()->AsSuperReference()); |
|
|
|
__ Push(result_register()); |
|
|
|
VisitForStackValue(expr->key()); |
|
|
|
EmitKeyedSuperPropertyLoad(expr); |
|
|
|
} |
|
|
|
context()->Plug(x0); |
|
|
|
} |
|
|
|
} |
|
|
@ -2464,6 +2598,43 @@ void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { |
|
|
|
Expression* callee = expr->expression(); |
|
|
|
DCHECK(callee->IsProperty()); |
|
|
|
Property* prop = callee->AsProperty(); |
|
|
|
DCHECK(prop->IsSuperAccess()); |
|
|
|
|
|
|
|
SetSourcePosition(prop->position()); |
|
|
|
|
|
|
|
// Load the function from the receiver.
|
|
|
|
const Register scratch = x10; |
|
|
|
SuperReference* super_ref = callee->AsProperty()->obj()->AsSuperReference(); |
|
|
|
EmitLoadHomeObject(super_ref); |
|
|
|
__ Push(x0); |
|
|
|
VisitForAccumulatorValue(super_ref->this_var()); |
|
|
|
__ Push(x0); |
|
|
|
__ Peek(scratch, kPointerSize); |
|
|
|
__ Push(x0, scratch); |
|
|
|
VisitForStackValue(prop->key()); |
|
|
|
|
|
|
|
// Stack here:
|
|
|
|
// - home_object
|
|
|
|
// - this (receiver)
|
|
|
|
// - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
|
|
|
|
// - home_object
|
|
|
|
// - key
|
|
|
|
__ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); |
|
|
|
|
|
|
|
// Replace home_object with target function.
|
|
|
|
__ Poke(x0, kPointerSize); |
|
|
|
|
|
|
|
// Stack here:
|
|
|
|
// - target function
|
|
|
|
// - this (receiver)
|
|
|
|
EmitCall(expr, CallICState::METHOD); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) { |
|
|
|
// Load the arguments.
|
|
|
|
ZoneList<Expression*>* args = expr->arguments(); |
|
|
@ -2478,7 +2649,7 @@ void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) { |
|
|
|
|
|
|
|
Handle<Code> ic = CallIC::initialize_stub( |
|
|
|
isolate(), arg_count, call_type); |
|
|
|
__ Mov(x3, Smi::FromInt(expr->CallFeedbackSlot())); |
|
|
|
__ Mov(x3, SmiFromSlot(expr->CallFeedbackSlot())); |
|
|
|
__ Peek(x1, (arg_count + 1) * kXRegSize); |
|
|
|
// Don't assign a type feedback id to the IC, since type feedback is provided
|
|
|
|
// by the vector above.
|
|
|
@ -2496,11 +2667,12 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { |
|
|
|
// Prepare to push a copy of the first argument or undefined if it doesn't
|
|
|
|
// exist.
|
|
|
|
if (arg_count > 0) { |
|
|
|
__ Peek(x10, arg_count * kXRegSize); |
|
|
|
__ Peek(x9, arg_count * kXRegSize); |
|
|
|
} else { |
|
|
|
__ LoadRoot(x10, Heap::kUndefinedValueRootIndex); |
|
|
|
__ LoadRoot(x9, Heap::kUndefinedValueRootIndex); |
|
|
|
} |
|
|
|
|
|
|
|
__ Ldr(x10, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
|
|
|
// Prepare to push the receiver of the enclosing function.
|
|
|
|
int receiver_offset = 2 + info_->scope()->num_parameters(); |
|
|
|
__ Ldr(x11, MemOperand(fp, receiver_offset * kPointerSize)); |
|
|
@ -2511,10 +2683,18 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { |
|
|
|
__ Mov(x13, Smi::FromInt(scope()->start_position())); |
|
|
|
|
|
|
|
// Push.
|
|
|
|
__ Push(x10, x11, x12, x13); |
|
|
|
__ Push(x9, x10, x11, x12, x13); |
|
|
|
|
|
|
|
// Do the runtime call.
|
|
|
|
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); |
|
|
|
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) { |
|
|
|
DCHECK(super_ref != NULL); |
|
|
|
__ ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
|
|
|
__ Push(x0); |
|
|
|
__ CallRuntime(Runtime::kGetPrototype, 1); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -2557,6 +2737,8 @@ void FullCodeGenerator::VisitCall(Call* expr) { |
|
|
|
// The runtime call returns a pair of values in x0 (function) and
|
|
|
|
// x1 (receiver). Touch up the stack with the right values.
|
|
|
|
__ PokePair(x1, x0, arg_count * kPointerSize); |
|
|
|
|
|
|
|
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS); |
|
|
|
} |
|
|
|
|
|
|
|
// Record source position for debugger.
|
|
|
@ -2592,6 +2774,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { |
|
|
|
__ Push(context_register(), x10); |
|
|
|
__ CallRuntime(Runtime::kLoadLookupSlot, 2); |
|
|
|
__ Push(x0, x1); // Receiver, function.
|
|
|
|
PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS); |
|
|
|
|
|
|
|
// If fast case code has been generated, emit code to push the
|
|
|
|
// function and receiver and have the slow path jump around this
|
|
|
@ -2614,9 +2797,12 @@ void FullCodeGenerator::VisitCall(Call* expr) { |
|
|
|
} else if (call_type == Call::PROPERTY_CALL) { |
|
|
|
Property* property = callee->AsProperty(); |
|
|
|
bool is_named_call = property->key()->IsPropertyName(); |
|
|
|
// super.x() is handled in EmitCallWithLoadIC.
|
|
|
|
if (property->IsSuperAccess() && is_named_call) { |
|
|
|
EmitSuperCallWithLoadIC(expr); |
|
|
|
if (property->IsSuperAccess()) { |
|
|
|
if (is_named_call) { |
|
|
|
EmitSuperCallWithLoadIC(expr); |
|
|
|
} else { |
|
|
|
EmitKeyedSuperCallWithLoadIC(expr); |
|
|
|
} |
|
|
|
} else { |
|
|
|
{ |
|
|
|
PreservePositionScope scope(masm()->positions_recorder()); |
|
|
@ -2628,6 +2814,12 @@ void FullCodeGenerator::VisitCall(Call* expr) { |
|
|
|
EmitKeyedCallWithLoadIC(expr, property->key()); |
|
|
|
} |
|
|
|
} |
|
|
|
} else if (call_type == Call::SUPER_CALL) { |
|
|
|
SuperReference* super_ref = callee->AsSuperReference(); |
|
|
|
EmitLoadSuperConstructor(super_ref); |
|
|
|
__ Push(result_register()); |
|
|
|
VisitForStackValue(super_ref->this_var()); |
|
|
|
EmitCall(expr, CallICState::METHOD); |
|
|
|
} else { |
|
|
|
DCHECK(call_type == Call::OTHER_CALL); |
|
|
|
// Call to an arbitrary expression not handled specially above.
|
|
|
@ -2656,7 +2848,12 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) { |
|
|
|
// Push constructor on the stack. If it's not a function it's used as
|
|
|
|
// receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
|
|
|
|
// ignored.
|
|
|
|
VisitForStackValue(expr->expression()); |
|
|
|
if (expr->expression()->IsSuperReference()) { |
|
|
|
EmitLoadSuperConstructor(expr->expression()->AsSuperReference()); |
|
|
|
__ Push(result_register()); |
|
|
|
} else { |
|
|
|
VisitForStackValue(expr->expression()); |
|
|
|
} |
|
|
|
|
|
|
|
// Push the arguments ("left-to-right") on the stack.
|
|
|
|
ZoneList<Expression*>* args = expr->arguments(); |
|
|
@ -2676,12 +2873,12 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) { |
|
|
|
// Record call targets in unoptimized code.
|
|
|
|
if (FLAG_pretenuring_call_new) { |
|
|
|
EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot()); |
|
|
|
DCHECK(expr->AllocationSiteFeedbackSlot() == |
|
|
|
expr->CallNewFeedbackSlot() + 1); |
|
|
|
DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() == |
|
|
|
expr->CallNewFeedbackSlot().ToInt() + 1); |
|
|
|
} |
|
|
|
|
|
|
|
__ LoadObject(x2, FeedbackVector()); |
|
|
|
__ Mov(x3, Smi::FromInt(expr->CallNewFeedbackSlot())); |
|
|
|
__ Mov(x3, SmiFromSlot(expr->CallNewFeedbackSlot())); |
|
|
|
|
|
|
|
CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET); |
|
|
|
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); |
|
|
@ -3004,6 +3201,32 @@ void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) { |
|
|
|
ZoneList<Expression*>* args = expr->arguments(); |
|
|
|
DCHECK(args->length() == 1); |
|
|
|
|
|
|
|
VisitForAccumulatorValue(args->at(0)); |
|
|
|
|
|
|
|
Label materialize_true, materialize_false; |
|
|
|
Label* if_true = NULL; |
|
|
|
Label* if_false = NULL; |
|
|
|
Label* fall_through = NULL; |
|
|
|
context()->PrepareTest(&materialize_true, &materialize_false, &if_true, |
|
|
|
&if_false, &fall_through); |
|
|
|
|
|
|
|
__ JumpIfSmi(x0, if_false); |
|
|
|
Register map = x10; |
|
|
|
Register type_reg = x11; |
|
|
|
__ Ldr(map, FieldMemOperand(x0, HeapObject::kMapOffset)); |
|
|
|
__ Ldrb(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
|
|
|
__ Sub(type_reg, type_reg, Operand(FIRST_JS_PROXY_TYPE)); |
|
|
|
__ Cmp(type_reg, Operand(LAST_JS_PROXY_TYPE - FIRST_JS_PROXY_TYPE)); |
|
|
|
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
|
|
|
Split(ls, if_true, if_false, fall_through); |
|
|
|
|
|
|
|
context()->Plug(if_true, if_false); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) { |
|
|
|
DCHECK(expr->arguments()->length() == 0); |
|
|
@ -3883,7 +4106,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
|
|
|
__ Mov(LoadDescriptor::NameRegister(), Operand(name)); |
|
|
|
if (FLAG_vector_ics) { |
|
|
|
__ Mov(VectorLoadICDescriptor::SlotRegister(), |
|
|
|
Smi::FromInt(expr->CallRuntimeFeedbackSlot())); |
|
|
|
SmiFromSlot(expr->CallRuntimeFeedbackSlot())); |
|
|
|
CallLoadIC(NOT_CONTEXTUAL); |
|
|
|
} else { |
|
|
|
CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); |
|
|
@ -4037,22 +4260,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { |
|
|
|
Comment cmnt(masm_, "[ CountOperation"); |
|
|
|
SetSourcePosition(expr->position()); |
|
|
|
|
|
|
|
// Expression can only be a property, a global or a (parameter or local)
|
|
|
|
// slot.
|
|
|
|
enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
|
|
|
LhsKind assign_type = VARIABLE; |
|
|
|
Property* prop = expr->expression()->AsProperty(); |
|
|
|
// In case of a property we use the uninitialized expression context
|
|
|
|
// of the key to detect a named property.
|
|
|
|
if (prop != NULL) { |
|
|
|
assign_type = |
|
|
|
(prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; |
|
|
|
if (prop->IsSuperAccess()) { |
|
|
|
// throw exception.
|
|
|
|
VisitSuperReference(prop->obj()->AsSuperReference()); |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
LhsKind assign_type = GetAssignType(prop); |
|
|
|
|
|
|
|
// Evaluate expression and get value.
|
|
|
|
if (assign_type == VARIABLE) { |
|
|
@ -4064,18 +4273,52 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { |
|
|
|
if (expr->is_postfix() && !context()->IsEffect()) { |
|
|
|
__ Push(xzr); |
|
|
|
} |
|
|
|
if (assign_type == NAMED_PROPERTY) { |
|
|
|
// Put the object both on the stack and in the register.
|
|
|
|
VisitForStackValue(prop->obj()); |
|
|
|
__ Peek(LoadDescriptor::ReceiverRegister(), 0); |
|
|
|
EmitNamedPropertyLoad(prop); |
|
|
|
} else { |
|
|
|
// KEYED_PROPERTY
|
|
|
|
VisitForStackValue(prop->obj()); |
|
|
|
VisitForStackValue(prop->key()); |
|
|
|
__ Peek(LoadDescriptor::ReceiverRegister(), 1 * kPointerSize); |
|
|
|
__ Peek(LoadDescriptor::NameRegister(), 0); |
|
|
|
EmitKeyedPropertyLoad(prop); |
|
|
|
switch (assign_type) { |
|
|
|
case NAMED_PROPERTY: { |
|
|
|
// Put the object both on the stack and in the register.
|
|
|
|
VisitForStackValue(prop->obj()); |
|
|
|
__ Peek(LoadDescriptor::ReceiverRegister(), 0); |
|
|
|
EmitNamedPropertyLoad(prop); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
case NAMED_SUPER_PROPERTY: { |
|
|
|
VisitForStackValue(prop->obj()->AsSuperReference()->this_var()); |
|
|
|
EmitLoadHomeObject(prop->obj()->AsSuperReference()); |
|
|
|
__ Push(result_register()); |
|
|
|
const Register scratch = x10; |
|
|
|
__ Peek(scratch, kPointerSize); |
|
|
|
__ Push(scratch, result_register()); |
|
|
|
EmitNamedSuperPropertyLoad(prop); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
case KEYED_SUPER_PROPERTY: { |
|
|
|
VisitForStackValue(prop->obj()->AsSuperReference()->this_var()); |
|
|
|
EmitLoadHomeObject(prop->obj()->AsSuperReference()); |
|
|
|
__ Push(result_register()); |
|
|
|
VisitForAccumulatorValue(prop->key()); |
|
|
|
__ Push(result_register()); |
|
|
|
const Register scratch1 = x10; |
|
|
|
const Register scratch2 = x11; |
|
|
|
__ Peek(scratch1, 2 * kPointerSize); |
|
|
|
__ Peek(scratch2, kPointerSize); |
|
|
|
__ Push(scratch1, scratch2, result_register()); |
|
|
|
EmitKeyedSuperPropertyLoad(prop); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
case KEYED_PROPERTY: { |
|
|
|
VisitForStackValue(prop->obj()); |
|
|
|
VisitForStackValue(prop->key()); |
|
|
|
__ Peek(LoadDescriptor::ReceiverRegister(), 1 * kPointerSize); |
|
|
|
__ Peek(LoadDescriptor::NameRegister(), 0); |
|
|
|
EmitKeyedPropertyLoad(prop); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
case VARIABLE: |
|
|
|
UNREACHABLE(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -4109,9 +4352,15 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { |
|
|
|
case NAMED_PROPERTY: |
|
|
|
__ Poke(x0, kPointerSize); |
|
|
|
break; |
|
|
|
case NAMED_SUPER_PROPERTY: |
|
|
|
__ Poke(x0, kPointerSize * 2); |
|
|
|
break; |
|
|
|
case KEYED_PROPERTY: |
|
|
|
__ Poke(x0, kPointerSize * 2); |
|
|
|
break; |
|
|
|
case KEYED_SUPER_PROPERTY: |
|
|
|
__ Poke(x0, kPointerSize * 3); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -4139,9 +4388,15 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { |
|
|
|
case NAMED_PROPERTY: |
|
|
|
__ Poke(x0, kXRegSize); |
|
|
|
break; |
|
|
|
case NAMED_SUPER_PROPERTY: |
|
|
|
__ Poke(x0, 2 * kXRegSize); |
|
|
|
break; |
|
|
|
case KEYED_PROPERTY: |
|
|
|
__ Poke(x0, 2 * kXRegSize); |
|
|
|
break; |
|
|
|
case KEYED_SUPER_PROPERTY: |
|
|
|
__ Poke(x0, 3 * kXRegSize); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -4199,6 +4454,28 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case NAMED_SUPER_PROPERTY: { |
|
|
|
EmitNamedSuperPropertyStore(prop); |
|
|
|
if (expr->is_postfix()) { |
|
|
|
if (!context()->IsEffect()) { |
|
|
|
context()->PlugTOS(); |
|
|
|
} |
|
|
|
} else { |
|
|
|
context()->Plug(x0); |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case KEYED_SUPER_PROPERTY: { |
|
|
|
EmitKeyedSuperPropertyStore(prop); |
|
|
|
if (expr->is_postfix()) { |
|
|
|
if (!context()->IsEffect()) { |
|
|
|
context()->PlugTOS(); |
|
|
|
} |
|
|
|
} else { |
|
|
|
context()->Plug(x0); |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case KEYED_PROPERTY: { |
|
|
|
__ Pop(StoreDescriptor::NameRegister()); |
|
|
|
__ Pop(StoreDescriptor::ReceiverRegister()); |
|
|
@ -4229,7 +4506,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
|
|
|
__ Mov(LoadDescriptor::NameRegister(), Operand(proxy->name())); |
|
|
|
if (FLAG_vector_ics) { |
|
|
|
__ Mov(VectorLoadICDescriptor::SlotRegister(), |
|
|
|
Smi::FromInt(proxy->VariableFeedbackSlot())); |
|
|
|
SmiFromSlot(proxy->VariableFeedbackSlot())); |
|
|
|
} |
|
|
|
// Use a regular load, not a contextual load, to avoid a reference
|
|
|
|
// error.
|
|
|
@ -4585,7 +4862,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { |
|
|
|
__ Peek(load_name, 2 * kPointerSize); |
|
|
|
if (FLAG_vector_ics) { |
|
|
|
__ Mov(VectorLoadICDescriptor::SlotRegister(), |
|
|
|
Smi::FromInt(expr->KeyedLoadFeedbackSlot())); |
|
|
|
SmiFromSlot(expr->KeyedLoadFeedbackSlot())); |
|
|
|
} |
|
|
|
Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code(); |
|
|
|
CallIC(ic, TypeFeedbackId::None()); |
|
|
@ -4605,7 +4882,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { |
|
|
|
__ LoadRoot(load_name, Heap::kdone_stringRootIndex); // "done"
|
|
|
|
if (FLAG_vector_ics) { |
|
|
|
__ Mov(VectorLoadICDescriptor::SlotRegister(), |
|
|
|
Smi::FromInt(expr->DoneFeedbackSlot())); |
|
|
|
SmiFromSlot(expr->DoneFeedbackSlot())); |
|
|
|
} |
|
|
|
CallLoadIC(NOT_CONTEXTUAL); // x0=result.done
|
|
|
|
// The ToBooleanStub argument (result.done) is in x0.
|
|
|
@ -4618,7 +4895,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { |
|
|
|
__ LoadRoot(load_name, Heap::kvalue_stringRootIndex); // "value"
|
|
|
|
if (FLAG_vector_ics) { |
|
|
|
__ Mov(VectorLoadICDescriptor::SlotRegister(), |
|
|
|
Smi::FromInt(expr->ValueFeedbackSlot())); |
|
|
|
SmiFromSlot(expr->ValueFeedbackSlot())); |
|
|
|
} |
|
|
|
CallLoadIC(NOT_CONTEXTUAL); // x0=result.value
|
|
|
|
context()->DropAndPlug(2, x0); // drop iter and g
|
|
|
@ -4640,7 +4917,7 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator, |
|
|
|
|
|
|
|
// The value stays in x0, and is ultimately read by the resumed generator, as
|
|
|
|
// if CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. Or it
|
|
|
|
// is read to throw the value when the resumed generator is already closed. r1
|
|
|
|
// is read to throw the value when the resumed generator is already closed. x1
|
|
|
|
// will hold the generator object until the activation has been resumed.
|
|
|
|
VisitForStackValue(generator); |
|
|
|
VisitForAccumulatorValue(value); |
|
|
@ -4754,16 +5031,18 @@ void FullCodeGenerator::EmitCreateIteratorResult(bool done) { |
|
|
|
Label gc_required; |
|
|
|
Label allocated; |
|
|
|
|
|
|
|
Handle<Map> map(isolate()->native_context()->iterator_result_map()); |
|
|
|
const int instance_size = 5 * kPointerSize; |
|
|
|
DCHECK_EQ(isolate()->native_context()->iterator_result_map()->instance_size(), |
|
|
|
instance_size); |
|
|
|
|
|
|
|
// Allocate and populate an object with this form: { value: VAL, done: DONE }
|
|
|
|
|
|
|
|
Register result = x0; |
|
|
|
__ Allocate(map->instance_size(), result, x10, x11, &gc_required, TAG_OBJECT); |
|
|
|
__ Allocate(instance_size, result, x10, x11, &gc_required, TAG_OBJECT); |
|
|
|
__ B(&allocated); |
|
|
|
|
|
|
|
__ Bind(&gc_required); |
|
|
|
__ Push(Smi::FromInt(map->instance_size())); |
|
|
|
__ Push(Smi::FromInt(instance_size)); |
|
|
|
__ CallRuntime(Runtime::kAllocateInNewSpace, 1); |
|
|
|
__ Ldr(context_register(), |
|
|
|
MemOperand(fp, StandardFrameConstants::kContextOffset)); |
|
|
@ -4774,11 +5053,13 @@ void FullCodeGenerator::EmitCreateIteratorResult(bool done) { |
|
|
|
Register boolean_done = x3; |
|
|
|
Register empty_fixed_array = x4; |
|
|
|
Register untagged_result = x5; |
|
|
|
__ Mov(map_reg, Operand(map)); |
|
|
|
__ Ldr(map_reg, GlobalObjectMemOperand()); |
|
|
|
__ Ldr(map_reg, FieldMemOperand(map_reg, GlobalObject::kNativeContextOffset)); |
|
|
|
__ 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())); |
|
|
|
DCHECK_EQ(map->instance_size(), 5 * kPointerSize); |
|
|
|
STATIC_ASSERT(JSObject::kPropertiesOffset + kPointerSize == |
|
|
|
JSObject::kElementsOffset); |
|
|
|
STATIC_ASSERT(JSGeneratorObject::kResultValuePropertyOffset + kPointerSize == |
|
|
|