From a58b9ba90bca337f8f83848e552e9174c4fbe223 Mon Sep 17 00:00:00 2001 From: "fschneider@chromium.org" Date: Mon, 29 Aug 2011 07:07:39 +0000 Subject: [PATCH] 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 --- src/arm/full-codegen-arm.cc | 208 +++++++++++------------------- src/ast.h | 11 +- src/hydrogen.cc | 20 +-- src/ia32/full-codegen-ia32.cc | 233 +++++++++++----------------------- src/mips/full-codegen-mips.cc | 217 +++++++++++-------------------- src/x64/full-codegen-x64.cc | 197 ++++++++++------------------ 6 files changed, 300 insertions(+), 586 deletions(-) diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 0973d0153..b58743de4 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -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 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 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. diff --git a/src/ast.h b/src/ast.h index 399d27894..74182d5dc 100644 --- a/src/ast.h +++ b/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; diff --git a/src/hydrogen.cc b/src/hydrogen.cc index a4fac71e6..dd3a591d6 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -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 { diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 3e42cc134..799ba73a2 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -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 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 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 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. diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index 9bacac453..cf48ccfd4 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -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 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 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. diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index ec71021b3..dd35053a6 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -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 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 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. -- 2.34.1