Remove code handling parameters rewritten to properties (aka synthetic properties).
After merging the new arguments branch, there is no need for this code anymore. TEST=all tests pass Review URL: http://codereview.chromium.org/7753030 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9031 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
cd3588d582
commit
a58b9ba90b
@ -47,7 +47,6 @@ namespace internal {
|
||||
|
||||
|
||||
static unsigned GetPropertyId(Property* property) {
|
||||
if (property->is_synthetic()) return AstNode::kNoNumber;
|
||||
return property->id();
|
||||
}
|
||||
|
||||
@ -694,104 +693,73 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
|
||||
Comment cmnt(masm_, "[ Declaration");
|
||||
ASSERT(variable != NULL); // Must have been resolved.
|
||||
Slot* slot = variable->AsSlot();
|
||||
Property* prop = variable->AsProperty();
|
||||
|
||||
if (slot != NULL) {
|
||||
switch (slot->type()) {
|
||||
case Slot::PARAMETER:
|
||||
case Slot::LOCAL:
|
||||
if (mode == Variable::CONST) {
|
||||
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
||||
__ str(ip, MemOperand(fp, SlotOffset(slot)));
|
||||
} else if (function != NULL) {
|
||||
VisitForAccumulatorValue(function);
|
||||
__ str(result_register(), MemOperand(fp, SlotOffset(slot)));
|
||||
}
|
||||
break;
|
||||
|
||||
case Slot::CONTEXT:
|
||||
// We bypass the general EmitSlotSearch because we know more about
|
||||
// this specific context.
|
||||
|
||||
// The variable in the decl always resides in the current function
|
||||
// context.
|
||||
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
|
||||
if (FLAG_debug_code) {
|
||||
// Check that we're not inside a with or catch context.
|
||||
__ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset));
|
||||
__ CompareRoot(r1, Heap::kWithContextMapRootIndex);
|
||||
__ Check(ne, "Declaration in with context.");
|
||||
__ CompareRoot(r1, Heap::kCatchContextMapRootIndex);
|
||||
__ Check(ne, "Declaration in catch context.");
|
||||
}
|
||||
if (mode == Variable::CONST) {
|
||||
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
||||
__ str(ip, ContextOperand(cp, slot->index()));
|
||||
// No write barrier since the_hole_value is in old space.
|
||||
} else if (function != NULL) {
|
||||
VisitForAccumulatorValue(function);
|
||||
__ str(result_register(), ContextOperand(cp, slot->index()));
|
||||
int offset = Context::SlotOffset(slot->index());
|
||||
// We know that we have written a function, which is not a smi.
|
||||
__ mov(r1, Operand(cp));
|
||||
__ RecordWrite(r1, Operand(offset), r2, result_register());
|
||||
}
|
||||
break;
|
||||
|
||||
case Slot::LOOKUP: {
|
||||
__ mov(r2, Operand(variable->name()));
|
||||
// Declaration nodes are always introduced in one of two modes.
|
||||
ASSERT(mode == Variable::VAR ||
|
||||
mode == Variable::CONST ||
|
||||
mode == Variable::LET);
|
||||
PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
|
||||
__ mov(r1, Operand(Smi::FromInt(attr)));
|
||||
// Push initial value, if any.
|
||||
// Note: For variables we must not push an initial value (such as
|
||||
// 'undefined') because we may have a (legal) redeclaration and we
|
||||
// must not destroy the current value.
|
||||
if (mode == Variable::CONST) {
|
||||
__ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
|
||||
__ Push(cp, r2, r1, r0);
|
||||
} else if (function != NULL) {
|
||||
__ Push(cp, r2, r1);
|
||||
// Push initial value for function declaration.
|
||||
VisitForStackValue(function);
|
||||
} else {
|
||||
__ mov(r0, Operand(Smi::FromInt(0))); // No initial value!
|
||||
__ Push(cp, r2, r1, r0);
|
||||
}
|
||||
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
|
||||
break;
|
||||
ASSERT(slot != NULL);
|
||||
switch (slot->type()) {
|
||||
case Slot::PARAMETER:
|
||||
case Slot::LOCAL:
|
||||
if (mode == Variable::CONST) {
|
||||
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
||||
__ str(ip, MemOperand(fp, SlotOffset(slot)));
|
||||
} else if (function != NULL) {
|
||||
VisitForAccumulatorValue(function);
|
||||
__ str(result_register(), MemOperand(fp, SlotOffset(slot)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
} else if (prop != NULL) {
|
||||
// A const declaration aliasing a parameter is an illegal redeclaration.
|
||||
ASSERT(mode != Variable::CONST);
|
||||
if (function != NULL) {
|
||||
// We are declaring a function that rewrites to a property.
|
||||
// Use (keyed) IC to set the initial value. We cannot visit the
|
||||
// rewrite because it's shared and we risk recording duplicate AST
|
||||
// IDs for bailouts from optimized code.
|
||||
ASSERT(prop->obj()->AsVariableProxy() != NULL);
|
||||
{ AccumulatorValueContext for_object(this);
|
||||
EmitVariableLoad(prop->obj()->AsVariableProxy());
|
||||
case Slot::CONTEXT:
|
||||
// We bypass the general EmitSlotSearch because we know more about
|
||||
// this specific context.
|
||||
|
||||
// The variable in the decl always resides in the current function
|
||||
// context.
|
||||
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
|
||||
if (FLAG_debug_code) {
|
||||
// Check that we're not inside a with or catch context.
|
||||
__ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset));
|
||||
__ CompareRoot(r1, Heap::kWithContextMapRootIndex);
|
||||
__ Check(ne, "Declaration in with context.");
|
||||
__ CompareRoot(r1, Heap::kCatchContextMapRootIndex);
|
||||
__ Check(ne, "Declaration in catch context.");
|
||||
}
|
||||
if (mode == Variable::CONST) {
|
||||
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
||||
__ str(ip, ContextOperand(cp, slot->index()));
|
||||
// No write barrier since the_hole_value is in old space.
|
||||
} else if (function != NULL) {
|
||||
VisitForAccumulatorValue(function);
|
||||
__ str(result_register(), ContextOperand(cp, slot->index()));
|
||||
int offset = Context::SlotOffset(slot->index());
|
||||
// We know that we have written a function, which is not a smi.
|
||||
__ mov(r1, Operand(cp));
|
||||
__ RecordWrite(r1, Operand(offset), r2, result_register());
|
||||
}
|
||||
break;
|
||||
|
||||
__ push(r0);
|
||||
VisitForAccumulatorValue(function);
|
||||
__ pop(r2);
|
||||
|
||||
ASSERT(prop->key()->AsLiteral() != NULL &&
|
||||
prop->key()->AsLiteral()->handle()->IsSmi());
|
||||
__ mov(r1, Operand(prop->key()->AsLiteral()->handle()));
|
||||
|
||||
Handle<Code> ic = is_strict_mode()
|
||||
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
|
||||
: isolate()->builtins()->KeyedStoreIC_Initialize();
|
||||
__ Call(ic);
|
||||
// Value in r0 is ignored (declarations are statements).
|
||||
case Slot::LOOKUP: {
|
||||
__ mov(r2, Operand(variable->name()));
|
||||
// Declaration nodes are always introduced in one of two modes.
|
||||
ASSERT(mode == Variable::VAR ||
|
||||
mode == Variable::CONST ||
|
||||
mode == Variable::LET);
|
||||
PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
|
||||
__ mov(r1, Operand(Smi::FromInt(attr)));
|
||||
// Push initial value, if any.
|
||||
// Note: For variables we must not push an initial value (such as
|
||||
// 'undefined') because we may have a (legal) redeclaration and we
|
||||
// must not destroy the current value.
|
||||
if (mode == Variable::CONST) {
|
||||
__ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
|
||||
__ Push(cp, r2, r1, r0);
|
||||
} else if (function != NULL) {
|
||||
__ Push(cp, r2, r1);
|
||||
// Push initial value for function declaration.
|
||||
VisitForStackValue(function);
|
||||
} else {
|
||||
__ mov(r0, Operand(Smi::FromInt(0))); // No initial value!
|
||||
__ Push(cp, r2, r1, r0);
|
||||
}
|
||||
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2272,36 +2240,10 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
|
||||
} else {
|
||||
// Call to a keyed property.
|
||||
// For a synthetic property use keyed load IC followed by function call,
|
||||
// for a regular property use EmitKeyedCallWithIC.
|
||||
if (prop->is_synthetic()) {
|
||||
// Do not visit the object and key subexpressions (they are shared
|
||||
// by all occurrences of the same rewritten parameter).
|
||||
ASSERT(prop->obj()->AsVariableProxy() != NULL);
|
||||
ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL);
|
||||
Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot();
|
||||
MemOperand operand = EmitSlotSearch(slot, r1);
|
||||
__ ldr(r1, operand);
|
||||
|
||||
ASSERT(prop->key()->AsLiteral() != NULL);
|
||||
ASSERT(prop->key()->AsLiteral()->handle()->IsSmi());
|
||||
__ mov(r0, Operand(prop->key()->AsLiteral()->handle()));
|
||||
|
||||
// Record source code position for IC call.
|
||||
SetSourcePosition(prop->position());
|
||||
|
||||
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
|
||||
__ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
|
||||
__ ldr(r1, GlobalObjectOperand());
|
||||
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
|
||||
__ Push(r0, r1); // Function, receiver.
|
||||
EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
|
||||
} else {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(prop->obj());
|
||||
}
|
||||
EmitKeyedCallWithIC(expr, prop->key());
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(prop->obj());
|
||||
}
|
||||
EmitKeyedCallWithIC(expr, prop->key());
|
||||
}
|
||||
} else {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
@ -3631,18 +3573,12 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
|
||||
|
||||
if (prop != NULL) {
|
||||
if (prop->is_synthetic()) {
|
||||
// Result of deleting parameters is false, even when they rewrite
|
||||
// to accesses on the arguments object.
|
||||
context()->Plug(false);
|
||||
} else {
|
||||
VisitForStackValue(prop->obj());
|
||||
VisitForStackValue(prop->key());
|
||||
__ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
|
||||
__ push(r1);
|
||||
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
|
||||
context()->Plug(r0);
|
||||
}
|
||||
VisitForStackValue(prop->obj());
|
||||
VisitForStackValue(prop->key());
|
||||
__ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
|
||||
__ push(r1);
|
||||
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
|
||||
context()->Plug(r0);
|
||||
} else if (var != NULL) {
|
||||
// Delete of an unqualified identifier is disallowed in strict mode
|
||||
// but "delete this" is.
|
||||
|
11
src/ast.h
11
src/ast.h
@ -1231,21 +1231,14 @@ class Slot: public Expression {
|
||||
|
||||
class Property: public Expression {
|
||||
public:
|
||||
// Synthetic properties are property lookups introduced by the system,
|
||||
// to objects that aren't visible to the user. Function calls to synthetic
|
||||
// properties should use the global object as receiver, not the base object
|
||||
// of the resolved Reference.
|
||||
enum Type { NORMAL, SYNTHETIC };
|
||||
Property(Isolate* isolate,
|
||||
Expression* obj,
|
||||
Expression* key,
|
||||
int pos,
|
||||
Type type = NORMAL)
|
||||
int pos)
|
||||
: Expression(isolate),
|
||||
obj_(obj),
|
||||
key_(key),
|
||||
pos_(pos),
|
||||
type_(type),
|
||||
is_monomorphic_(false),
|
||||
is_array_length_(false),
|
||||
is_string_length_(false),
|
||||
@ -1260,7 +1253,6 @@ class Property: public Expression {
|
||||
Expression* obj() const { return obj_; }
|
||||
Expression* key() const { return key_; }
|
||||
virtual int position() const { return pos_; }
|
||||
bool is_synthetic() const { return type_ == SYNTHETIC; }
|
||||
|
||||
bool IsStringLength() const { return is_string_length_; }
|
||||
bool IsStringAccess() const { return is_string_access_; }
|
||||
@ -1276,7 +1268,6 @@ class Property: public Expression {
|
||||
Expression* obj_;
|
||||
Expression* key_;
|
||||
int pos_;
|
||||
Type type_;
|
||||
|
||||
SmallMapList receiver_types_;
|
||||
bool is_monomorphic_ : 1;
|
||||
|
@ -5074,19 +5074,13 @@ void HGraphBuilder::VisitDelete(UnaryOperation* expr) {
|
||||
// The subexpression does not have side effects.
|
||||
return ast_context()->ReturnValue(graph()->GetConstantFalse());
|
||||
} else if (prop != NULL) {
|
||||
if (prop->is_synthetic()) {
|
||||
// Result of deleting parameters is false, even when they rewrite
|
||||
// to accesses on the arguments object.
|
||||
return ast_context()->ReturnValue(graph()->GetConstantFalse());
|
||||
} else {
|
||||
CHECK_ALIVE(VisitForValue(prop->obj()));
|
||||
CHECK_ALIVE(VisitForValue(prop->key()));
|
||||
HValue* key = Pop();
|
||||
HValue* obj = Pop();
|
||||
HValue* context = environment()->LookupContext();
|
||||
HDeleteProperty* instr = new(zone()) HDeleteProperty(context, obj, key);
|
||||
return ast_context()->ReturnInstruction(instr, expr->id());
|
||||
}
|
||||
CHECK_ALIVE(VisitForValue(prop->obj()));
|
||||
CHECK_ALIVE(VisitForValue(prop->key()));
|
||||
HValue* key = Pop();
|
||||
HValue* obj = Pop();
|
||||
HValue* context = environment()->LookupContext();
|
||||
HDeleteProperty* instr = new(zone()) HDeleteProperty(context, obj, key);
|
||||
return ast_context()->ReturnInstruction(instr, expr->id());
|
||||
} else if (var->is_global()) {
|
||||
Bailout("delete with global variable");
|
||||
} else {
|
||||
|
@ -46,7 +46,6 @@ namespace internal {
|
||||
|
||||
|
||||
static unsigned GetPropertyId(Property* property) {
|
||||
if (property->is_synthetic()) return AstNode::kNoNumber;
|
||||
return property->id();
|
||||
}
|
||||
|
||||
@ -690,105 +689,73 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
|
||||
Comment cmnt(masm_, "[ Declaration");
|
||||
ASSERT(variable != NULL); // Must have been resolved.
|
||||
Slot* slot = variable->AsSlot();
|
||||
Property* prop = variable->AsProperty();
|
||||
|
||||
if (slot != NULL) {
|
||||
switch (slot->type()) {
|
||||
case Slot::PARAMETER:
|
||||
case Slot::LOCAL:
|
||||
if (mode == Variable::CONST) {
|
||||
__ mov(Operand(ebp, SlotOffset(slot)),
|
||||
Immediate(isolate()->factory()->the_hole_value()));
|
||||
} else if (function != NULL) {
|
||||
VisitForAccumulatorValue(function);
|
||||
__ mov(Operand(ebp, SlotOffset(slot)), result_register());
|
||||
}
|
||||
break;
|
||||
|
||||
case Slot::CONTEXT:
|
||||
// We bypass the general EmitSlotSearch because we know more about
|
||||
// this specific context.
|
||||
|
||||
// The variable in the decl always resides in the current function
|
||||
// context.
|
||||
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
|
||||
if (FLAG_debug_code) {
|
||||
// Check that we're not inside a with or catch context.
|
||||
__ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
|
||||
__ cmp(ebx, isolate()->factory()->with_context_map());
|
||||
__ Check(not_equal, "Declaration in with context.");
|
||||
__ cmp(ebx, isolate()->factory()->catch_context_map());
|
||||
__ Check(not_equal, "Declaration in catch context.");
|
||||
}
|
||||
if (mode == Variable::CONST) {
|
||||
__ mov(ContextOperand(esi, slot->index()),
|
||||
Immediate(isolate()->factory()->the_hole_value()));
|
||||
// No write barrier since the hole value is in old space.
|
||||
} else if (function != NULL) {
|
||||
VisitForAccumulatorValue(function);
|
||||
__ mov(ContextOperand(esi, slot->index()), result_register());
|
||||
int offset = Context::SlotOffset(slot->index());
|
||||
__ mov(ebx, esi);
|
||||
__ RecordWrite(ebx, offset, result_register(), ecx);
|
||||
}
|
||||
break;
|
||||
|
||||
case Slot::LOOKUP: {
|
||||
__ push(esi);
|
||||
__ push(Immediate(variable->name()));
|
||||
// Declaration nodes are always introduced in one of two modes.
|
||||
ASSERT(mode == Variable::VAR ||
|
||||
mode == Variable::CONST ||
|
||||
mode == Variable::LET);
|
||||
PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
|
||||
__ push(Immediate(Smi::FromInt(attr)));
|
||||
// Push initial value, if any.
|
||||
// Note: For variables we must not push an initial value (such as
|
||||
// 'undefined') because we may have a (legal) redeclaration and we
|
||||
// must not destroy the current value.
|
||||
increment_stack_height(3);
|
||||
if (mode == Variable::CONST) {
|
||||
__ push(Immediate(isolate()->factory()->the_hole_value()));
|
||||
increment_stack_height();
|
||||
} else if (function != NULL) {
|
||||
VisitForStackValue(function);
|
||||
} else {
|
||||
__ push(Immediate(Smi::FromInt(0))); // No initial value!
|
||||
increment_stack_height();
|
||||
}
|
||||
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
|
||||
decrement_stack_height(4);
|
||||
break;
|
||||
ASSERT(slot != NULL);
|
||||
switch (slot->type()) {
|
||||
case Slot::PARAMETER:
|
||||
case Slot::LOCAL:
|
||||
if (mode == Variable::CONST) {
|
||||
__ mov(Operand(ebp, SlotOffset(slot)),
|
||||
Immediate(isolate()->factory()->the_hole_value()));
|
||||
} else if (function != NULL) {
|
||||
VisitForAccumulatorValue(function);
|
||||
__ mov(Operand(ebp, SlotOffset(slot)), result_register());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
} else if (prop != NULL) {
|
||||
// A const declaration aliasing a parameter is an illegal redeclaration.
|
||||
ASSERT(mode != Variable::CONST);
|
||||
if (function != NULL) {
|
||||
// We are declaring a function that rewrites to a property.
|
||||
// Use (keyed) IC to set the initial value. We cannot visit the
|
||||
// rewrite because it's shared and we risk recording duplicate AST
|
||||
// IDs for bailouts from optimized code.
|
||||
ASSERT(prop->obj()->AsVariableProxy() != NULL);
|
||||
{ AccumulatorValueContext for_object(this);
|
||||
EmitVariableLoad(prop->obj()->AsVariableProxy());
|
||||
case Slot::CONTEXT:
|
||||
// We bypass the general EmitSlotSearch because we know more about
|
||||
// this specific context.
|
||||
|
||||
// The variable in the decl always resides in the current function
|
||||
// context.
|
||||
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
|
||||
if (FLAG_debug_code) {
|
||||
// Check that we're not inside a with or catch context.
|
||||
__ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
|
||||
__ cmp(ebx, isolate()->factory()->with_context_map());
|
||||
__ Check(not_equal, "Declaration in with context.");
|
||||
__ cmp(ebx, isolate()->factory()->catch_context_map());
|
||||
__ Check(not_equal, "Declaration in catch context.");
|
||||
}
|
||||
if (mode == Variable::CONST) {
|
||||
__ mov(ContextOperand(esi, slot->index()),
|
||||
Immediate(isolate()->factory()->the_hole_value()));
|
||||
// No write barrier since the hole value is in old space.
|
||||
} else if (function != NULL) {
|
||||
VisitForAccumulatorValue(function);
|
||||
__ mov(ContextOperand(esi, slot->index()), result_register());
|
||||
int offset = Context::SlotOffset(slot->index());
|
||||
__ mov(ebx, esi);
|
||||
__ RecordWrite(ebx, offset, result_register(), ecx);
|
||||
}
|
||||
break;
|
||||
|
||||
__ push(eax);
|
||||
increment_stack_height();
|
||||
VisitForAccumulatorValue(function);
|
||||
__ pop(edx);
|
||||
decrement_stack_height();
|
||||
|
||||
ASSERT(prop->key()->AsLiteral() != NULL &&
|
||||
prop->key()->AsLiteral()->handle()->IsSmi());
|
||||
__ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle()));
|
||||
|
||||
Handle<Code> ic = is_strict_mode()
|
||||
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
|
||||
: isolate()->builtins()->KeyedStoreIC_Initialize();
|
||||
__ call(ic);
|
||||
case Slot::LOOKUP: {
|
||||
__ push(esi);
|
||||
__ push(Immediate(variable->name()));
|
||||
// Declaration nodes are always introduced in one of two modes.
|
||||
ASSERT(mode == Variable::VAR ||
|
||||
mode == Variable::CONST ||
|
||||
mode == Variable::LET);
|
||||
PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
|
||||
__ push(Immediate(Smi::FromInt(attr)));
|
||||
// Push initial value, if any.
|
||||
// Note: For variables we must not push an initial value (such as
|
||||
// 'undefined') because we may have a (legal) redeclaration and we
|
||||
// must not destroy the current value.
|
||||
increment_stack_height(3);
|
||||
if (mode == Variable::CONST) {
|
||||
__ push(Immediate(isolate()->factory()->the_hole_value()));
|
||||
increment_stack_height();
|
||||
} else if (function != NULL) {
|
||||
VisitForStackValue(function);
|
||||
} else {
|
||||
__ push(Immediate(Smi::FromInt(0))); // No initial value!
|
||||
increment_stack_height();
|
||||
}
|
||||
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
|
||||
decrement_stack_height(4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1824,21 +1791,11 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
|
||||
case KEYED_PROPERTY: {
|
||||
__ push(eax); // Preserve value.
|
||||
increment_stack_height();
|
||||
if (prop->is_synthetic()) {
|
||||
ASSERT(prop->obj()->AsVariableProxy() != NULL);
|
||||
ASSERT(prop->key()->AsLiteral() != NULL);
|
||||
{ AccumulatorValueContext for_object(this);
|
||||
EmitVariableLoad(prop->obj()->AsVariableProxy());
|
||||
}
|
||||
__ mov(edx, eax);
|
||||
__ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle()));
|
||||
} else {
|
||||
VisitForStackValue(prop->obj());
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
__ mov(ecx, eax);
|
||||
__ pop(edx);
|
||||
decrement_stack_height();
|
||||
}
|
||||
VisitForStackValue(prop->obj());
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
__ mov(ecx, eax);
|
||||
__ pop(edx);
|
||||
decrement_stack_height();
|
||||
__ pop(eax); // Restore value.
|
||||
decrement_stack_height();
|
||||
Handle<Code> ic = is_strict_mode()
|
||||
@ -2275,40 +2232,10 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
|
||||
} else {
|
||||
// Call to a keyed property.
|
||||
// For a synthetic property use keyed load IC followed by function call,
|
||||
// for a regular property use EmitKeyedCallWithIC.
|
||||
if (prop->is_synthetic()) {
|
||||
// Do not visit the object and key subexpressions (they are shared
|
||||
// by all occurrences of the same rewritten parameter).
|
||||
ASSERT(prop->obj()->AsVariableProxy() != NULL);
|
||||
ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL);
|
||||
Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot();
|
||||
MemOperand operand = EmitSlotSearch(slot, edx);
|
||||
__ mov(edx, operand);
|
||||
|
||||
ASSERT(prop->key()->AsLiteral() != NULL);
|
||||
ASSERT(prop->key()->AsLiteral()->handle()->IsSmi());
|
||||
__ mov(eax, prop->key()->AsLiteral()->handle());
|
||||
|
||||
// Record source code position for IC call.
|
||||
SetSourcePosition(prop->position());
|
||||
|
||||
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
|
||||
__ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
|
||||
// Push result (function).
|
||||
__ push(eax);
|
||||
increment_stack_height();
|
||||
// Push Global receiver.
|
||||
__ mov(ecx, GlobalObjectOperand());
|
||||
__ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
|
||||
increment_stack_height();
|
||||
EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
|
||||
} else {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(prop->obj());
|
||||
}
|
||||
EmitKeyedCallWithIC(expr, prop->key());
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(prop->obj());
|
||||
}
|
||||
EmitKeyedCallWithIC(expr, prop->key());
|
||||
}
|
||||
} else {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
@ -3688,18 +3615,12 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
|
||||
|
||||
if (prop != NULL) {
|
||||
if (prop->is_synthetic()) {
|
||||
// Result of deleting parameters is false, even when they rewrite
|
||||
// to accesses on the arguments object.
|
||||
context()->Plug(false);
|
||||
} else {
|
||||
VisitForStackValue(prop->obj());
|
||||
VisitForStackValue(prop->key());
|
||||
__ push(Immediate(Smi::FromInt(strict_mode_flag())));
|
||||
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
|
||||
decrement_stack_height(2);
|
||||
context()->Plug(eax);
|
||||
}
|
||||
VisitForStackValue(prop->obj());
|
||||
VisitForStackValue(prop->key());
|
||||
__ push(Immediate(Smi::FromInt(strict_mode_flag())));
|
||||
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
|
||||
decrement_stack_height(2);
|
||||
context()->Plug(eax);
|
||||
} else if (var != NULL) {
|
||||
// Delete of an unqualified identifier is disallowed in strict mode
|
||||
// but "delete this" is.
|
||||
|
@ -55,7 +55,6 @@ namespace internal {
|
||||
|
||||
|
||||
static unsigned GetPropertyId(Property* property) {
|
||||
if (property->is_synthetic()) return AstNode::kNoNumber;
|
||||
return property->id();
|
||||
}
|
||||
|
||||
@ -697,109 +696,77 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
|
||||
Comment cmnt(masm_, "[ Declaration");
|
||||
ASSERT(variable != NULL); // Must have been resolved.
|
||||
Slot* slot = variable->AsSlot();
|
||||
Property* prop = variable->AsProperty();
|
||||
|
||||
if (slot != NULL) {
|
||||
switch (slot->type()) {
|
||||
case Slot::PARAMETER:
|
||||
case Slot::LOCAL:
|
||||
if (mode == Variable::CONST) {
|
||||
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
|
||||
__ sw(t0, MemOperand(fp, SlotOffset(slot)));
|
||||
} else if (function != NULL) {
|
||||
VisitForAccumulatorValue(function);
|
||||
__ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
|
||||
}
|
||||
break;
|
||||
|
||||
case Slot::CONTEXT:
|
||||
// We bypass the general EmitSlotSearch because we know more about
|
||||
// this specific context.
|
||||
|
||||
// The variable in the decl always resides in the current function
|
||||
// context.
|
||||
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
|
||||
if (FLAG_debug_code) {
|
||||
// Check that we're not inside a with or catch context.
|
||||
__ lw(a1, FieldMemOperand(cp, HeapObject::kMapOffset));
|
||||
__ LoadRoot(t0, Heap::kWithContextMapRootIndex);
|
||||
__ Check(ne, "Declaration in with context.",
|
||||
a1, Operand(t0));
|
||||
__ LoadRoot(t0, Heap::kCatchContextMapRootIndex);
|
||||
__ Check(ne, "Declaration in catch context.",
|
||||
a1, Operand(t0));
|
||||
}
|
||||
if (mode == Variable::CONST) {
|
||||
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
|
||||
__ sw(at, ContextOperand(cp, slot->index()));
|
||||
// No write barrier since the_hole_value is in old space.
|
||||
} else if (function != NULL) {
|
||||
VisitForAccumulatorValue(function);
|
||||
__ sw(result_register(), ContextOperand(cp, slot->index()));
|
||||
int offset = Context::SlotOffset(slot->index());
|
||||
// We know that we have written a function, which is not a smi.
|
||||
__ mov(a1, cp);
|
||||
__ RecordWrite(a1, Operand(offset), a2, result_register());
|
||||
}
|
||||
break;
|
||||
|
||||
case Slot::LOOKUP: {
|
||||
__ li(a2, Operand(variable->name()));
|
||||
// Declaration nodes are always introduced in one of two modes.
|
||||
ASSERT(mode == Variable::VAR ||
|
||||
mode == Variable::CONST ||
|
||||
mode == Variable::LET);
|
||||
PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
|
||||
__ li(a1, Operand(Smi::FromInt(attr)));
|
||||
// Push initial value, if any.
|
||||
// Note: For variables we must not push an initial value (such as
|
||||
// 'undefined') because we may have a (legal) redeclaration and we
|
||||
// must not destroy the current value.
|
||||
if (mode == Variable::CONST) {
|
||||
__ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
|
||||
__ Push(cp, a2, a1, a0);
|
||||
} else if (function != NULL) {
|
||||
__ Push(cp, a2, a1);
|
||||
// Push initial value for function declaration.
|
||||
VisitForStackValue(function);
|
||||
} else {
|
||||
ASSERT(Smi::FromInt(0) == 0);
|
||||
// No initial value!
|
||||
__ mov(a0, zero_reg); // Operand(Smi::FromInt(0)));
|
||||
__ Push(cp, a2, a1, a0);
|
||||
}
|
||||
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
|
||||
break;
|
||||
ASSERT(slot != NULL);
|
||||
switch (slot->type()) {
|
||||
case Slot::PARAMETER:
|
||||
case Slot::LOCAL:
|
||||
if (mode == Variable::CONST) {
|
||||
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
|
||||
__ sw(t0, MemOperand(fp, SlotOffset(slot)));
|
||||
} else if (function != NULL) {
|
||||
VisitForAccumulatorValue(function);
|
||||
__ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
} else if (prop != NULL) {
|
||||
// A const declaration aliasing a parameter is an illegal redeclaration.
|
||||
ASSERT(mode != Variable::CONST);
|
||||
if (function != NULL) {
|
||||
// We are declaring a function that rewrites to a property.
|
||||
// Use (keyed) IC to set the initial value. We cannot visit the
|
||||
// rewrite because it's shared and we risk recording duplicate AST
|
||||
// IDs for bailouts from optimized code.
|
||||
ASSERT(prop->obj()->AsVariableProxy() != NULL);
|
||||
{ AccumulatorValueContext for_object(this);
|
||||
EmitVariableLoad(prop->obj()->AsVariableProxy());
|
||||
case Slot::CONTEXT:
|
||||
// We bypass the general EmitSlotSearch because we know more about
|
||||
// this specific context.
|
||||
|
||||
// The variable in the decl always resides in the current function
|
||||
// context.
|
||||
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
|
||||
if (FLAG_debug_code) {
|
||||
// Check that we're not inside a with or catch context.
|
||||
__ lw(a1, FieldMemOperand(cp, HeapObject::kMapOffset));
|
||||
__ LoadRoot(t0, Heap::kWithContextMapRootIndex);
|
||||
__ Check(ne, "Declaration in with context.",
|
||||
a1, Operand(t0));
|
||||
__ LoadRoot(t0, Heap::kCatchContextMapRootIndex);
|
||||
__ Check(ne, "Declaration in catch context.",
|
||||
a1, Operand(t0));
|
||||
}
|
||||
if (mode == Variable::CONST) {
|
||||
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
|
||||
__ sw(at, ContextOperand(cp, slot->index()));
|
||||
// No write barrier since the_hole_value is in old space.
|
||||
} else if (function != NULL) {
|
||||
VisitForAccumulatorValue(function);
|
||||
__ sw(result_register(), ContextOperand(cp, slot->index()));
|
||||
int offset = Context::SlotOffset(slot->index());
|
||||
// We know that we have written a function, which is not a smi.
|
||||
__ mov(a1, cp);
|
||||
__ RecordWrite(a1, Operand(offset), a2, result_register());
|
||||
}
|
||||
break;
|
||||
|
||||
__ push(result_register());
|
||||
VisitForAccumulatorValue(function);
|
||||
__ mov(a0, result_register());
|
||||
__ pop(a2);
|
||||
|
||||
ASSERT(prop->key()->AsLiteral() != NULL &&
|
||||
prop->key()->AsLiteral()->handle()->IsSmi());
|
||||
__ li(a1, Operand(prop->key()->AsLiteral()->handle()));
|
||||
|
||||
Handle<Code> ic = is_strict_mode()
|
||||
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
|
||||
: isolate()->builtins()->KeyedStoreIC_Initialize();
|
||||
__ Call(ic);
|
||||
// Value in v0 is ignored (declarations are statements).
|
||||
case Slot::LOOKUP: {
|
||||
__ li(a2, Operand(variable->name()));
|
||||
// Declaration nodes are always introduced in one of two modes.
|
||||
ASSERT(mode == Variable::VAR ||
|
||||
mode == Variable::CONST ||
|
||||
mode == Variable::LET);
|
||||
PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
|
||||
__ li(a1, Operand(Smi::FromInt(attr)));
|
||||
// Push initial value, if any.
|
||||
// Note: For variables we must not push an initial value (such as
|
||||
// 'undefined') because we may have a (legal) redeclaration and we
|
||||
// must not destroy the current value.
|
||||
if (mode == Variable::CONST) {
|
||||
__ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
|
||||
__ Push(cp, a2, a1, a0);
|
||||
} else if (function != NULL) {
|
||||
__ Push(cp, a2, a1);
|
||||
// Push initial value for function declaration.
|
||||
VisitForStackValue(function);
|
||||
} else {
|
||||
ASSERT(Smi::FromInt(0) == 0);
|
||||
// No initial value!
|
||||
__ mov(a0, zero_reg); // Operand(Smi::FromInt(0)));
|
||||
__ Push(cp, a2, a1, a0);
|
||||
}
|
||||
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2286,36 +2253,10 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
|
||||
} else {
|
||||
// Call to a keyed property.
|
||||
// For a synthetic property use keyed load IC followed by function call,
|
||||
// for a regular property use EmitKeyedCallWithIC.
|
||||
if (prop->is_synthetic()) {
|
||||
// Do not visit the object and key subexpressions (they are shared
|
||||
// by all occurrences of the same rewritten parameter).
|
||||
ASSERT(prop->obj()->AsVariableProxy() != NULL);
|
||||
ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL);
|
||||
Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot();
|
||||
MemOperand operand = EmitSlotSearch(slot, a1);
|
||||
__ lw(a1, operand);
|
||||
|
||||
ASSERT(prop->key()->AsLiteral() != NULL);
|
||||
ASSERT(prop->key()->AsLiteral()->handle()->IsSmi());
|
||||
__ li(a0, Operand(prop->key()->AsLiteral()->handle()));
|
||||
|
||||
// Record source code position for IC call.
|
||||
SetSourcePosition(prop->position());
|
||||
|
||||
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
|
||||
__ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
|
||||
__ lw(a1, GlobalObjectOperand());
|
||||
__ lw(a1, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
|
||||
__ Push(v0, a1); // Function, receiver.
|
||||
EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
|
||||
} else {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(prop->obj());
|
||||
}
|
||||
EmitKeyedCallWithIC(expr, prop->key());
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(prop->obj());
|
||||
}
|
||||
EmitKeyedCallWithIC(expr, prop->key());
|
||||
}
|
||||
} else {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
@ -3653,18 +3594,12 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
|
||||
|
||||
if (prop != NULL) {
|
||||
if (prop->is_synthetic()) {
|
||||
// Result of deleting parameters is false, even when they rewrite
|
||||
// to accesses on the arguments object.
|
||||
context()->Plug(false);
|
||||
} else {
|
||||
VisitForStackValue(prop->obj());
|
||||
VisitForStackValue(prop->key());
|
||||
__ li(a1, Operand(Smi::FromInt(strict_mode_flag())));
|
||||
__ push(a1);
|
||||
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
|
||||
context()->Plug(v0);
|
||||
}
|
||||
VisitForStackValue(prop->obj());
|
||||
VisitForStackValue(prop->key());
|
||||
__ li(a1, Operand(Smi::FromInt(strict_mode_flag())));
|
||||
__ push(a1);
|
||||
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
|
||||
context()->Plug(v0);
|
||||
} else if (var != NULL) {
|
||||
// Delete of an unqualified identifier is disallowed in strict mode
|
||||
// but "delete this" is.
|
||||
|
@ -45,7 +45,6 @@ namespace internal {
|
||||
|
||||
|
||||
static unsigned GetPropertyId(Property* property) {
|
||||
if (property->is_synthetic()) return AstNode::kNoNumber;
|
||||
return property->id();
|
||||
}
|
||||
|
||||
@ -665,97 +664,69 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
|
||||
Comment cmnt(masm_, "[ Declaration");
|
||||
ASSERT(variable != NULL); // Must have been resolved.
|
||||
Slot* slot = variable->AsSlot();
|
||||
Property* prop = variable->AsProperty();
|
||||
|
||||
if (slot != NULL) {
|
||||
switch (slot->type()) {
|
||||
case Slot::PARAMETER:
|
||||
case Slot::LOCAL:
|
||||
if (mode == Variable::CONST) {
|
||||
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
|
||||
__ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister);
|
||||
} else if (function != NULL) {
|
||||
VisitForAccumulatorValue(function);
|
||||
__ movq(Operand(rbp, SlotOffset(slot)), result_register());
|
||||
}
|
||||
break;
|
||||
|
||||
case Slot::CONTEXT:
|
||||
// We bypass the general EmitSlotSearch because we know more about
|
||||
// this specific context.
|
||||
|
||||
// The variable in the decl always resides in the current function
|
||||
// context.
|
||||
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
|
||||
if (FLAG_debug_code) {
|
||||
// Check that we're not inside a with or catch context.
|
||||
__ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
|
||||
__ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
|
||||
__ Check(not_equal, "Declaration in with context.");
|
||||
__ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
|
||||
__ Check(not_equal, "Declaration in catch context.");
|
||||
}
|
||||
if (mode == Variable::CONST) {
|
||||
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
|
||||
__ movq(ContextOperand(rsi, slot->index()), kScratchRegister);
|
||||
// No write barrier since the hole value is in old space.
|
||||
} else if (function != NULL) {
|
||||
VisitForAccumulatorValue(function);
|
||||
__ movq(ContextOperand(rsi, slot->index()), result_register());
|
||||
int offset = Context::SlotOffset(slot->index());
|
||||
__ movq(rbx, rsi);
|
||||
__ RecordWrite(rbx, offset, result_register(), rcx);
|
||||
}
|
||||
break;
|
||||
|
||||
case Slot::LOOKUP: {
|
||||
__ push(rsi);
|
||||
__ Push(variable->name());
|
||||
// Declaration nodes are always introduced in one of two modes.
|
||||
ASSERT(mode == Variable::VAR ||
|
||||
mode == Variable::CONST ||
|
||||
mode == Variable::LET);
|
||||
PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
|
||||
__ Push(Smi::FromInt(attr));
|
||||
// Push initial value, if any.
|
||||
// Note: For variables we must not push an initial value (such as
|
||||
// 'undefined') because we may have a (legal) redeclaration and we
|
||||
// must not destroy the current value.
|
||||
if (mode == Variable::CONST) {
|
||||
__ PushRoot(Heap::kTheHoleValueRootIndex);
|
||||
} else if (function != NULL) {
|
||||
VisitForStackValue(function);
|
||||
} else {
|
||||
__ Push(Smi::FromInt(0)); // no initial value!
|
||||
}
|
||||
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
|
||||
break;
|
||||
ASSERT(slot != NULL);
|
||||
switch (slot->type()) {
|
||||
case Slot::PARAMETER:
|
||||
case Slot::LOCAL:
|
||||
if (mode == Variable::CONST) {
|
||||
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
|
||||
__ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister);
|
||||
} else if (function != NULL) {
|
||||
VisitForAccumulatorValue(function);
|
||||
__ movq(Operand(rbp, SlotOffset(slot)), result_register());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
} else if (prop != NULL) {
|
||||
// A const declaration aliasing a parameter is an illegal redeclaration.
|
||||
ASSERT(mode != Variable::CONST);
|
||||
if (function != NULL) {
|
||||
// We are declaring a function that rewrites to a property.
|
||||
// Use (keyed) IC to set the initial value. We cannot visit the
|
||||
// rewrite because it's shared and we risk recording duplicate AST
|
||||
// IDs for bailouts from optimized code.
|
||||
ASSERT(prop->obj()->AsVariableProxy() != NULL);
|
||||
{ AccumulatorValueContext for_object(this);
|
||||
EmitVariableLoad(prop->obj()->AsVariableProxy());
|
||||
case Slot::CONTEXT:
|
||||
// We bypass the general EmitSlotSearch because we know more about
|
||||
// this specific context.
|
||||
|
||||
// The variable in the decl always resides in the current function
|
||||
// context.
|
||||
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
|
||||
if (FLAG_debug_code) {
|
||||
// Check that we're not inside a with or catch context.
|
||||
__ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
|
||||
__ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
|
||||
__ Check(not_equal, "Declaration in with context.");
|
||||
__ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
|
||||
__ Check(not_equal, "Declaration in catch context.");
|
||||
}
|
||||
__ push(rax);
|
||||
VisitForAccumulatorValue(function);
|
||||
__ pop(rdx);
|
||||
ASSERT(prop->key()->AsLiteral() != NULL &&
|
||||
prop->key()->AsLiteral()->handle()->IsSmi());
|
||||
__ Move(rcx, prop->key()->AsLiteral()->handle());
|
||||
if (mode == Variable::CONST) {
|
||||
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
|
||||
__ movq(ContextOperand(rsi, slot->index()), kScratchRegister);
|
||||
// No write barrier since the hole value is in old space.
|
||||
} else if (function != NULL) {
|
||||
VisitForAccumulatorValue(function);
|
||||
__ movq(ContextOperand(rsi, slot->index()), result_register());
|
||||
int offset = Context::SlotOffset(slot->index());
|
||||
__ movq(rbx, rsi);
|
||||
__ RecordWrite(rbx, offset, result_register(), rcx);
|
||||
}
|
||||
break;
|
||||
|
||||
Handle<Code> ic = is_strict_mode()
|
||||
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
|
||||
: isolate()->builtins()->KeyedStoreIC_Initialize();
|
||||
__ call(ic);
|
||||
case Slot::LOOKUP: {
|
||||
__ push(rsi);
|
||||
__ Push(variable->name());
|
||||
// Declaration nodes are always introduced in one of two modes.
|
||||
ASSERT(mode == Variable::VAR ||
|
||||
mode == Variable::CONST ||
|
||||
mode == Variable::LET);
|
||||
PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
|
||||
__ Push(Smi::FromInt(attr));
|
||||
// Push initial value, if any.
|
||||
// Note: For variables we must not push an initial value (such as
|
||||
// 'undefined') because we may have a (legal) redeclaration and we
|
||||
// must not destroy the current value.
|
||||
if (mode == Variable::CONST) {
|
||||
__ PushRoot(Heap::kTheHoleValueRootIndex);
|
||||
} else if (function != NULL) {
|
||||
VisitForStackValue(function);
|
||||
} else {
|
||||
__ Push(Smi::FromInt(0)); // no initial value!
|
||||
}
|
||||
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2169,38 +2140,10 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
|
||||
} else {
|
||||
// Call to a keyed property.
|
||||
// For a synthetic property use keyed load IC followed by function call,
|
||||
// for a regular property use EmitKeyedCallWithIC.
|
||||
if (prop->is_synthetic()) {
|
||||
// Do not visit the object and key subexpressions (they are shared
|
||||
// by all occurrences of the same rewritten parameter).
|
||||
ASSERT(prop->obj()->AsVariableProxy() != NULL);
|
||||
ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL);
|
||||
Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot();
|
||||
MemOperand operand = EmitSlotSearch(slot, rdx);
|
||||
__ movq(rdx, operand);
|
||||
|
||||
ASSERT(prop->key()->AsLiteral() != NULL);
|
||||
ASSERT(prop->key()->AsLiteral()->handle()->IsSmi());
|
||||
__ Move(rax, prop->key()->AsLiteral()->handle());
|
||||
|
||||
// Record source code position for IC call.
|
||||
SetSourcePosition(prop->position());
|
||||
|
||||
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
|
||||
__ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
|
||||
// Push result (function).
|
||||
__ push(rax);
|
||||
// Push Global receiver.
|
||||
__ movq(rcx, GlobalObjectOperand());
|
||||
__ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset));
|
||||
EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
|
||||
} else {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(prop->obj());
|
||||
}
|
||||
EmitKeyedCallWithIC(expr, prop->key());
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(prop->obj());
|
||||
}
|
||||
EmitKeyedCallWithIC(expr, prop->key());
|
||||
}
|
||||
} else {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
@ -3566,17 +3509,11 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
|
||||
|
||||
if (prop != NULL) {
|
||||
if (prop->is_synthetic()) {
|
||||
// Result of deleting parameters is false, even when they rewrite
|
||||
// to accesses on the arguments object.
|
||||
context()->Plug(false);
|
||||
} else {
|
||||
VisitForStackValue(prop->obj());
|
||||
VisitForStackValue(prop->key());
|
||||
__ Push(Smi::FromInt(strict_mode_flag()));
|
||||
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
|
||||
context()->Plug(rax);
|
||||
}
|
||||
VisitForStackValue(prop->obj());
|
||||
VisitForStackValue(prop->key());
|
||||
__ Push(Smi::FromInt(strict_mode_flag()));
|
||||
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
|
||||
context()->Plug(rax);
|
||||
} else if (var != NULL) {
|
||||
// Delete of an unqualified identifier is disallowed in strict mode
|
||||
// but "delete this" is.
|
||||
|
Loading…
Reference in New Issue
Block a user