From: verwaest@chromium.org Date: Wed, 5 Jun 2013 08:43:25 +0000 (+0000) Subject: Remove the optimized construct stub. X-Git-Tag: upstream/4.7.83~14009 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5e8679beeab1fa1761e43001637c15ce2b881139;p=platform%2Fupstream%2Fv8.git Remove the optimized construct stub. R=mstarzinger@chromium.org Review URL: https://chromiumcodereview.appspot.com/15993016 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14946 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 912caed..39300e3 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -3091,151 +3091,6 @@ Handle KeyedStoreStubCompiler::CompileStorePolymorphic( } -Handle ConstructStubCompiler::CompileConstructStub( - Handle function) { - // ----------- S t a t e ------------- - // -- r0 : argc - // -- r1 : constructor - // -- lr : return address - // -- [sp] : last argument - // ----------------------------------- - Label generic_stub_call; - - // Use r7 for holding undefined which is used in several places below. - __ LoadRoot(r7, Heap::kUndefinedValueRootIndex); - -#ifdef ENABLE_DEBUGGER_SUPPORT - // Check to see whether there are any break points in the function code. If - // there are jump to the generic constructor stub which calls the actual - // code for the function thereby hitting the break points. - __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); - __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kDebugInfoOffset)); - __ cmp(r2, r7); - __ b(ne, &generic_stub_call); -#endif - - // Load the initial map and verify that it is in fact a map. - // r1: constructor function - // r7: undefined - __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); - __ JumpIfSmi(r2, &generic_stub_call); - __ CompareObjectType(r2, r3, r4, MAP_TYPE); - __ b(ne, &generic_stub_call); - -#ifdef DEBUG - // Cannot construct functions this way. - // r0: argc - // r1: constructor function - // r2: initial map - // r7: undefined - __ CompareInstanceType(r2, r3, JS_FUNCTION_TYPE); - __ Check(ne, "Function constructed by construct stub."); -#endif - - // Now allocate the JSObject in new space. - // r0: argc - // r1: constructor function - // r2: initial map - // r7: undefined - ASSERT(function->has_initial_map()); - __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset)); -#ifdef DEBUG - int instance_size = function->initial_map()->instance_size(); - __ cmp(r3, Operand(instance_size >> kPointerSizeLog2)); - __ Check(eq, "Instance size of initial map changed."); -#endif - __ Allocate(r3, r4, r5, r6, &generic_stub_call, SIZE_IN_WORDS); - - // Allocated the JSObject, now initialize the fields. Map is set to initial - // map and properties and elements are set to empty fixed array. - // r0: argc - // r1: constructor function - // r2: initial map - // r3: object size (in words) - // r4: JSObject (not tagged) - // r7: undefined - __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex); - __ mov(r5, r4); - ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset); - __ str(r2, MemOperand(r5, kPointerSize, PostIndex)); - ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset); - __ str(r6, MemOperand(r5, kPointerSize, PostIndex)); - ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset); - __ str(r6, MemOperand(r5, kPointerSize, PostIndex)); - - // Calculate the location of the first argument. The stack contains only the - // argc arguments. - __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2)); - - // Fill all the in-object properties with undefined. - // r0: argc - // r1: first argument - // r3: object size (in words) - // r4: JSObject (not tagged) - // r5: First in-object property of JSObject (not tagged) - // r7: undefined - // Fill the initialized properties with a constant value or a passed argument - // depending on the this.x = ...; assignment in the function. - Handle shared(function->shared()); - for (int i = 0; i < shared->this_property_assignments_count(); i++) { - if (shared->IsThisPropertyAssignmentArgument(i)) { - Label not_passed, next; - // Check if the argument assigned to the property is actually passed. - int arg_number = shared->GetThisPropertyAssignmentArgument(i); - __ cmp(r0, Operand(arg_number)); - __ b(le, ¬_passed); - // Argument passed - find it on the stack. - __ ldr(r2, MemOperand(r1, (arg_number + 1) * -kPointerSize)); - __ str(r2, MemOperand(r5, kPointerSize, PostIndex)); - __ b(&next); - __ bind(¬_passed); - // Set the property to undefined. - __ str(r7, MemOperand(r5, kPointerSize, PostIndex)); - __ bind(&next); - } else { - // Set the property to the constant value. - Handle constant(shared->GetThisPropertyAssignmentConstant(i), - isolate()); - __ mov(r2, Operand(constant)); - __ str(r2, MemOperand(r5, kPointerSize, PostIndex)); - } - } - - // Fill the unused in-object property fields with undefined. - for (int i = shared->this_property_assignments_count(); - i < function->initial_map()->inobject_properties(); - i++) { - __ str(r7, MemOperand(r5, kPointerSize, PostIndex)); - } - - // r0: argc - // r4: JSObject (not tagged) - // Move argc to r1 and the JSObject to return to r0 and tag it. - __ mov(r1, r0); - __ mov(r0, r4); - __ orr(r0, r0, Operand(kHeapObjectTag)); - - // r0: JSObject - // r1: argc - // Remove caller arguments and receiver from the stack and return. - __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2)); - __ add(sp, sp, Operand(kPointerSize)); - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->constructed_objects(), 1, r1, r2); - __ IncrementCounter(counters->constructed_objects_stub(), 1, r1, r2); - __ Jump(lr); - - // Jump to the generic stub in case the specialized code cannot handle the - // construction. - __ bind(&generic_stub_call); - Handle code = isolate()->builtins()->JSConstructStubGeneric(); - __ Jump(code, RelocInfo::CODE_TARGET); - - // Return the generated code. - return GetCode(); -} - - #undef __ #define __ ACCESS_MASM(masm) diff --git a/src/ast.h b/src/ast.h index 373adf9..41c910a 100644 --- a/src/ast.h +++ b/src/ast.h @@ -2161,12 +2161,6 @@ class FunctionLiteral: public Expression { int materialized_literal_count() { return materialized_literal_count_; } int expected_property_count() { return expected_property_count_; } int handler_count() { return handler_count_; } - bool has_only_simple_this_property_assignments() { - return HasOnlySimpleThisPropertyAssignments::decode(bitfield_); - } - Handle this_property_assignments() { - return this_property_assignments_; - } int parameter_count() { return parameter_count_; } bool AllowsLazyCompilation(); @@ -2221,8 +2215,6 @@ class FunctionLiteral: public Expression { int materialized_literal_count, int expected_property_count, int handler_count, - bool has_only_simple_this_property_assignments, - Handle this_property_assignments, int parameter_count, Type type, ParameterFlag has_duplicate_parameters, @@ -2233,7 +2225,6 @@ class FunctionLiteral: public Expression { name_(name), scope_(scope), body_(body), - this_property_assignments_(this_property_assignments), inferred_name_(isolate->factory()->empty_string()), materialized_literal_count_(materialized_literal_count), expected_property_count_(expected_property_count), @@ -2241,8 +2232,6 @@ class FunctionLiteral: public Expression { parameter_count_(parameter_count), function_token_position_(RelocInfo::kNoPosition) { bitfield_ = - HasOnlySimpleThisPropertyAssignments::encode( - has_only_simple_this_property_assignments) | IsExpression::encode(type != DECLARATION) | IsAnonymous::encode(type == ANONYMOUS_EXPRESSION) | Pretenure::encode(false) | @@ -2256,7 +2245,6 @@ class FunctionLiteral: public Expression { Handle name_; Scope* scope_; ZoneList* body_; - Handle this_property_assignments_; Handle inferred_name_; AstProperties ast_properties_; @@ -2267,14 +2255,13 @@ class FunctionLiteral: public Expression { int function_token_position_; unsigned bitfield_; - class HasOnlySimpleThisPropertyAssignments: public BitField {}; - class IsExpression: public BitField {}; - class IsAnonymous: public BitField {}; - class Pretenure: public BitField {}; - class HasDuplicateParameters: public BitField {}; - class IsFunction: public BitField {}; - class IsParenthesized: public BitField {}; - class IsGenerator: public BitField {}; + class IsExpression: public BitField {}; + class IsAnonymous: public BitField {}; + class Pretenure: public BitField {}; + class HasDuplicateParameters: public BitField {}; + class IsFunction: public BitField {}; + class IsParenthesized: public BitField {}; + class IsGenerator: public BitField {}; }; @@ -3097,8 +3084,6 @@ class AstNodeFactory BASE_EMBEDDED { int materialized_literal_count, int expected_property_count, int handler_count, - bool has_only_simple_this_property_assignments, - Handle this_property_assignments, int parameter_count, FunctionLiteral::ParameterFlag has_duplicate_parameters, FunctionLiteral::Type type, @@ -3108,7 +3093,6 @@ class AstNodeFactory BASE_EMBEDDED { FunctionLiteral* lit = new(zone_) FunctionLiteral( isolate_, name, scope, body, materialized_literal_count, expected_property_count, handler_count, - has_only_simple_this_property_assignments, this_property_assignments, parameter_count, type, has_duplicate_parameters, is_function, is_parenthesized, is_generator); // Top-level literal doesn't count for the AST's properties. diff --git a/src/compiler.cc b/src/compiler.cc index e44cd41..5320fc9 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -771,13 +771,6 @@ static bool InstallFullCode(CompilationInfo* info) { int expected = lit->expected_property_count(); SetExpectedNofPropertiesFromEstimate(shared, expected); - // Set the optimization hints after performing lazy compilation, as - // these are not set when the function is set up as a lazily - // compiled function. - shared->SetThisPropertyAssignmentsInfo( - lit->has_only_simple_this_property_assignments(), - *lit->this_property_assignments()); - // Check the function has compiled code. ASSERT(shared->is_compiled()); shared->set_code_age(0); @@ -1121,9 +1114,6 @@ void Compiler::SetFunctionInfo(Handle function_info, function_info->set_is_anonymous(lit->is_anonymous()); function_info->set_is_toplevel(is_toplevel); function_info->set_inferred_name(*lit->inferred_name()); - function_info->SetThisPropertyAssignmentsInfo( - lit->has_only_simple_this_property_assignments(), - *lit->this_property_assignments()); function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation()); function_info->set_allows_lazy_compilation_without_context( lit->AllowsLazyCompilationWithoutContext()); diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc index c4da47c..b8237a6 100644 --- a/src/heap-snapshot-generator.cc +++ b/src/heap-snapshot-generator.cc @@ -1210,10 +1210,6 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences( SetInternalReference(obj, entry, "inferred_name", shared->inferred_name(), SharedFunctionInfo::kInferredNameOffset); - SetInternalReference(obj, entry, - "this_property_assignments", - shared->this_property_assignments(), - SharedFunctionInfo::kThisPropertyAssignmentsOffset); SetWeakReference(obj, entry, 1, shared->initial_map(), SharedFunctionInfo::kInitialMapOffset); diff --git a/src/heap.cc b/src/heap.cc index 625fde3..5e88aca 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -3377,7 +3377,6 @@ MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) { share->set_debug_info(undefined_value(), SKIP_WRITE_BARRIER); share->set_inferred_name(empty_string(), SKIP_WRITE_BARRIER); share->set_initial_map(undefined_value(), SKIP_WRITE_BARRIER); - share->set_this_property_assignments(undefined_value(), SKIP_WRITE_BARRIER); share->set_ast_node_count(0); share->set_stress_deopt_counter(FLAG_deopt_every_n_times); share->set_counters(0); @@ -3392,7 +3391,6 @@ MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) { share->set_function_token_position(0); // All compiler hints default to false or 0. share->set_compiler_hints(0); - share->set_this_property_assignments_count(0); share->set_opt_count(0); return share; @@ -4161,20 +4159,6 @@ MaybeObject* Heap::AllocateArgumentsObject(Object* callee, int length) { } -static bool HasDuplicates(DescriptorArray* descriptors) { - int count = descriptors->number_of_descriptors(); - if (count > 1) { - Name* prev_key = descriptors->GetKey(0); - for (int i = 1; i != count; i++) { - Name* current_key = descriptors->GetKey(i); - if (prev_key == current_key) return true; - prev_key = current_key; - } - } - return false; -} - - MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) { ASSERT(!fun->has_initial_map()); @@ -4209,48 +4193,6 @@ MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) { map->set_prototype(prototype); ASSERT(map->has_fast_object_elements()); - // If the function has only simple this property assignments add - // field descriptors for these to the initial map as the object - // cannot be constructed without having these properties. Guard by - // the inline_new flag so we only change the map if we generate a - // specialized construct stub. - ASSERT(in_object_properties <= Map::kMaxPreAllocatedPropertyFields); - if (!fun->shared()->is_generator() && - fun->shared()->CanGenerateInlineConstructor(prototype)) { - int count = fun->shared()->this_property_assignments_count(); - if (count > in_object_properties) { - // Inline constructor can only handle inobject properties. - fun->shared()->ForbidInlineConstructor(); - } else { - DescriptorArray* descriptors; - MaybeObject* maybe_descriptors = DescriptorArray::Allocate(count); - if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; - - DescriptorArray::WhitenessWitness witness(descriptors); - for (int i = 0; i < count; i++) { - String* name = fun->shared()->GetThisPropertyAssignmentName(i); - ASSERT(name->IsInternalizedString()); - // TODO(verwaest): Since we cannot update the boilerplate's map yet, - // initialize to the worst case. - FieldDescriptor field(name, i, NONE, Representation::Tagged()); - descriptors->Set(i, &field, witness); - } - descriptors->Sort(); - - // The descriptors may contain duplicates because the compiler does not - // guarantee the uniqueness of property names (it would have required - // quadratic time). Once the descriptors are sorted we can check for - // duplicates in linear time. - if (HasDuplicates(descriptors)) { - fun->shared()->ForbidInlineConstructor(); - } else { - map->InitializeDescriptors(descriptors); - map->set_pre_allocated_property_fields(count); - map->set_unused_property_fields(in_object_properties - count); - } - } - } - if (!fun->shared()->is_generator()) { fun->shared()->StartInobjectSlackTracking(map); } diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index 7cb7811..691e9a6 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -3178,145 +3178,6 @@ Handle BaseLoadStubCompiler::CompilePolymorphicIC( } -// Specialized stub for constructing objects from functions which only have only -// simple assignments of the form this.x = ...; in their body. -Handle ConstructStubCompiler::CompileConstructStub( - Handle function) { - // ----------- S t a t e ------------- - // -- eax : argc - // -- edi : constructor - // -- esp[0] : return address - // -- esp[4] : last argument - // ----------------------------------- - Label generic_stub_call; -#ifdef ENABLE_DEBUGGER_SUPPORT - // Check to see whether there are any break points in the function code. If - // there are jump to the generic constructor stub which calls the actual - // code for the function thereby hitting the break points. - __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); - __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset)); - __ cmp(ebx, factory()->undefined_value()); - __ j(not_equal, &generic_stub_call); -#endif - - // Load the initial map and verify that it is in fact a map. - // edi: constructor - __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); - // Will both indicate a NULL and a Smi. - __ JumpIfSmi(ebx, &generic_stub_call); - __ CmpObjectType(ebx, MAP_TYPE, ecx); - __ j(not_equal, &generic_stub_call); - -#ifdef DEBUG - // Cannot construct functions this way. - // ebx: initial map - __ CmpInstanceType(ebx, JS_FUNCTION_TYPE); - __ Check(not_equal, "Function constructed by construct stub."); -#endif - - // Now allocate the JSObject on the heap by moving the new space allocation - // top forward. - // ebx: initial map - ASSERT(function->has_initial_map()); - int instance_size = function->initial_map()->instance_size(); -#ifdef DEBUG - __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset)); - __ shl(ecx, kPointerSizeLog2); - __ cmp(ecx, Immediate(instance_size)); - __ Check(equal, "Instance size of initial map changed."); -#endif - __ Allocate(instance_size, edx, ecx, no_reg, &generic_stub_call, - NO_ALLOCATION_FLAGS); - - // Allocated the JSObject, now initialize the fields and add the heap tag. - // ebx: initial map - // edx: JSObject (untagged) - __ mov(Operand(edx, JSObject::kMapOffset), ebx); - __ mov(ebx, factory()->empty_fixed_array()); - __ mov(Operand(edx, JSObject::kPropertiesOffset), ebx); - __ mov(Operand(edx, JSObject::kElementsOffset), ebx); - - // Push the allocated object to the stack. This is the object that will be - // returned (after it is tagged). - __ push(edx); - - // eax: argc - // edx: JSObject (untagged) - // Load the address of the first in-object property into edx. - __ lea(edx, Operand(edx, JSObject::kHeaderSize)); - // Calculate the location of the first argument. The stack contains the - // allocated object and the return address on top of the argc arguments. - __ lea(ecx, Operand(esp, eax, times_4, 1 * kPointerSize)); - - // Use edi for holding undefined which is used in several places below. - __ mov(edi, factory()->undefined_value()); - - // eax: argc - // ecx: first argument - // edx: first in-object property of the JSObject - // edi: undefined - // Fill the initialized properties with a constant value or a passed argument - // depending on the this.x = ...; assignment in the function. - Handle shared(function->shared()); - for (int i = 0; i < shared->this_property_assignments_count(); i++) { - if (shared->IsThisPropertyAssignmentArgument(i)) { - // Check if the argument assigned to the property is actually passed. - // If argument is not passed the property is set to undefined, - // otherwise find it on the stack. - int arg_number = shared->GetThisPropertyAssignmentArgument(i); - __ mov(ebx, edi); - __ cmp(eax, arg_number); - if (CpuFeatures::IsSupported(CMOV)) { - CpuFeatureScope use_cmov(masm(), CMOV); - __ cmov(above, ebx, Operand(ecx, arg_number * -kPointerSize)); - } else { - Label not_passed; - __ j(below_equal, ¬_passed); - __ mov(ebx, Operand(ecx, arg_number * -kPointerSize)); - __ bind(¬_passed); - } - // Store value in the property. - __ mov(Operand(edx, i * kPointerSize), ebx); - } else { - // Set the property to the constant value. - Handle constant(shared->GetThisPropertyAssignmentConstant(i), - isolate()); - __ mov(Operand(edx, i * kPointerSize), Immediate(constant)); - } - } - - // Fill the unused in-object property fields with undefined. - for (int i = shared->this_property_assignments_count(); - i < function->initial_map()->inobject_properties(); - i++) { - __ mov(Operand(edx, i * kPointerSize), edi); - } - - // Move argc to ebx and retrieve and tag the JSObject to return. - __ mov(ebx, eax); - __ pop(eax); - __ or_(eax, Immediate(kHeapObjectTag)); - - // Remove caller arguments and receiver from the stack and return. - __ pop(ecx); - __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize)); - __ push(ecx); - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->constructed_objects(), 1); - __ IncrementCounter(counters->constructed_objects_stub(), 1); - __ ret(0); - - // Jump to the generic stub in case the specialized code cannot handle the - // construction. - __ bind(&generic_stub_call); - Handle code = isolate()->builtins()->JSConstructStubGeneric(); - __ jmp(code, RelocInfo::CODE_TARGET); - - // Return the generated code. - return GetCode(); -} - - #undef __ #define __ ACCESS_MASM(masm) diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc index a19b964..63fde97 100644 --- a/src/mips/stub-cache-mips.cc +++ b/src/mips/stub-cache-mips.cc @@ -3143,157 +3143,6 @@ Handle KeyedStoreStubCompiler::CompileStorePolymorphic( } -Handle ConstructStubCompiler::CompileConstructStub( - Handle function) { - // a0 : argc - // a1 : constructor - // ra : return address - // [sp] : last argument - Label generic_stub_call; - - // Use t7 for holding undefined which is used in several places below. - __ LoadRoot(t7, Heap::kUndefinedValueRootIndex); - -#ifdef ENABLE_DEBUGGER_SUPPORT - // Check to see whether there are any break points in the function code. If - // there are jump to the generic constructor stub which calls the actual - // code for the function thereby hitting the break points. - __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); - __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset)); - __ Branch(&generic_stub_call, ne, a2, Operand(t7)); -#endif - - // Load the initial map and verify that it is in fact a map. - // a1: constructor function - // t7: undefined - __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset)); - __ JumpIfSmi(a2, &generic_stub_call); - __ GetObjectType(a2, a3, t0); - __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE)); - -#ifdef DEBUG - // Cannot construct functions this way. - // a0: argc - // a1: constructor function - // a2: initial map - // t7: undefined - __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset)); - __ Check(ne, "Function constructed by construct stub.", - a3, Operand(JS_FUNCTION_TYPE)); -#endif - - // Now allocate the JSObject in new space. - // a0: argc - // a1: constructor function - // a2: initial map - // t7: undefined - ASSERT(function->has_initial_map()); - __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset)); -#ifdef DEBUG - int instance_size = function->initial_map()->instance_size(); - __ Check(eq, "Instance size of initial map changed.", - a3, Operand(instance_size >> kPointerSizeLog2)); -#endif - __ Allocate(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS); - - // Allocated the JSObject, now initialize the fields. Map is set to initial - // map and properties and elements are set to empty fixed array. - // a0: argc - // a1: constructor function - // a2: initial map - // a3: object size (in words) - // t4: JSObject (not tagged) - // t7: undefined - __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex); - __ mov(t5, t4); - __ sw(a2, MemOperand(t5, JSObject::kMapOffset)); - __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset)); - __ sw(t6, MemOperand(t5, JSObject::kElementsOffset)); - __ Addu(t5, t5, Operand(3 * kPointerSize)); - ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset); - ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset); - ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset); - - - // Calculate the location of the first argument. The stack contains only the - // argc arguments. - __ sll(a1, a0, kPointerSizeLog2); - __ Addu(a1, a1, sp); - - // Fill all the in-object properties with undefined. - // a0: argc - // a1: first argument - // a3: object size (in words) - // t4: JSObject (not tagged) - // t5: First in-object property of JSObject (not tagged) - // t7: undefined - // Fill the initialized properties with a constant value or a passed argument - // depending on the this.x = ...; assignment in the function. - Handle shared(function->shared()); - for (int i = 0; i < shared->this_property_assignments_count(); i++) { - if (shared->IsThisPropertyAssignmentArgument(i)) { - Label not_passed, next; - // Check if the argument assigned to the property is actually passed. - int arg_number = shared->GetThisPropertyAssignmentArgument(i); - __ Branch(¬_passed, less_equal, a0, Operand(arg_number)); - // Argument passed - find it on the stack. - __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize)); - __ sw(a2, MemOperand(t5)); - __ Addu(t5, t5, kPointerSize); - __ jmp(&next); - __ bind(¬_passed); - // Set the property to undefined. - __ sw(t7, MemOperand(t5)); - __ Addu(t5, t5, Operand(kPointerSize)); - __ bind(&next); - } else { - // Set the property to the constant value. - Handle constant( - shared->GetThisPropertyAssignmentConstant(i), isolate()); - __ li(a2, Operand(constant)); - __ sw(a2, MemOperand(t5)); - __ Addu(t5, t5, kPointerSize); - } - } - - // Fill the unused in-object property fields with undefined. - for (int i = shared->this_property_assignments_count(); - i < function->initial_map()->inobject_properties(); - i++) { - __ sw(t7, MemOperand(t5)); - __ Addu(t5, t5, kPointerSize); - } - - // a0: argc - // t4: JSObject (not tagged) - // Move argc to a1 and the JSObject to return to v0 and tag it. - __ mov(a1, a0); - __ mov(v0, t4); - __ Or(v0, v0, Operand(kHeapObjectTag)); - - // v0: JSObject - // a1: argc - // Remove caller arguments and receiver from the stack and return. - __ sll(t0, a1, kPointerSizeLog2); - __ Addu(sp, sp, t0); - __ Addu(sp, sp, Operand(kPointerSize)); - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->constructed_objects(), 1, a1, a2); - __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2); - __ Ret(); - - // Jump to the generic stub in case the specialized code cannot handle the - // construction. - __ bind(&generic_stub_call); - Handle generic_construct_stub = - isolate()->builtins()->JSConstructStubGeneric(); - __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); - - // Return the generated code. - return GetCode(); -} - - #undef __ #define __ ACCESS_MASM(masm) diff --git a/src/objects-inl.h b/src/objects-inl.h index be4af06..956d088 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -4460,8 +4460,6 @@ ACCESSORS(SharedFunctionInfo, function_data, Object, kFunctionDataOffset) ACCESSORS(SharedFunctionInfo, script, Object, kScriptOffset) ACCESSORS(SharedFunctionInfo, debug_info, Object, kDebugInfoOffset) ACCESSORS(SharedFunctionInfo, inferred_name, String, kInferredNameOffset) -ACCESSORS(SharedFunctionInfo, this_property_assignments, Object, - kThisPropertyAssignmentsOffset) SMI_ACCESSORS(SharedFunctionInfo, ast_node_count, kAstNodeCountOffset) @@ -4478,10 +4476,6 @@ BOOL_ACCESSORS(SharedFunctionInfo, start_position_and_type, is_expression, BOOL_ACCESSORS(SharedFunctionInfo, start_position_and_type, is_toplevel, kIsTopLevelBit) -BOOL_GETTER(SharedFunctionInfo, - compiler_hints, - has_only_simple_this_property_assignments, - kHasOnlySimpleThisPropertyAssignments) BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, allows_lazy_compilation, @@ -4514,8 +4508,6 @@ SMI_ACCESSORS(SharedFunctionInfo, function_token_position, kFunctionTokenPositionOffset) SMI_ACCESSORS(SharedFunctionInfo, compiler_hints, kCompilerHintsOffset) -SMI_ACCESSORS(SharedFunctionInfo, this_property_assignments_count, - kThisPropertyAssignmentsCountOffset) SMI_ACCESSORS(SharedFunctionInfo, opt_count, kOptCountOffset) SMI_ACCESSORS(SharedFunctionInfo, counters, kCountersOffset) SMI_ACCESSORS(SharedFunctionInfo, @@ -4567,13 +4559,10 @@ PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, compiler_hints, kCompilerHintsOffset) -PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, - this_property_assignments_count, - kThisPropertyAssignmentsCountOffset) -PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, opt_count, kOptCountOffset) +PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, opt_count, kOptCountOffset) -PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, counters, kCountersOffset) -PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, +PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, counters, kCountersOffset) +PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, stress_deopt_counter, kStressDeoptCounterOffset) #endif diff --git a/src/objects-printer.cc b/src/objects-printer.cc index f312794..549c9ff 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -885,10 +885,6 @@ void SharedFunctionInfo::SharedFunctionInfoPrint(FILE* out) { PrintF(out, "\n - debug info = "); debug_info()->ShortPrint(out); PrintF(out, "\n - length = %d", length()); - PrintF(out, "\n - has_only_simple_this_property_assignments = %d", - has_only_simple_this_property_assignments()); - PrintF(out, "\n - this_property_assignments = "); - this_property_assignments()->ShortPrint(out); PrintF(out, "\n - optimized_code_map = "); optimized_code_map()->ShortPrint(out); PrintF(out, "\n"); diff --git a/src/objects.cc b/src/objects.cc index c9cc5a4..ca1c650 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -9647,114 +9647,6 @@ int SharedFunctionInfo::CalculateInObjectProperties() { } -bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) { - // Check the basic conditions for generating inline constructor code. - if (!FLAG_inline_new - || !has_only_simple_this_property_assignments() - || is_generator() - || this_property_assignments_count() == 0) { - return false; - } - - Isolate* isolate = GetIsolate(); - Heap* heap = isolate->heap(); - - // Traverse the proposed prototype chain looking for properties of the - // same names as are set by the inline constructor. - for (Object* obj = prototype; - obj != heap->null_value(); - obj = obj->GetPrototype(isolate)) { - JSReceiver* receiver = JSReceiver::cast(obj); - for (int i = 0; i < this_property_assignments_count(); i++) { - LookupResult result(heap->isolate()); - String* name = GetThisPropertyAssignmentName(i); - receiver->LocalLookup(name, &result); - if (result.IsFound()) { - switch (result.type()) { - case NORMAL: - case FIELD: - case CONSTANT_FUNCTION: - break; - case INTERCEPTOR: - case CALLBACKS: - case HANDLER: - return false; - case TRANSITION: - case NONEXISTENT: - UNREACHABLE(); - break; - } - } - } - } - - return true; -} - - -void SharedFunctionInfo::ForbidInlineConstructor() { - set_compiler_hints(BooleanBit::set(compiler_hints(), - kHasOnlySimpleThisPropertyAssignments, - false)); -} - - -void SharedFunctionInfo::SetThisPropertyAssignmentsInfo( - bool only_simple_this_property_assignments, - FixedArray* assignments) { - set_compiler_hints(BooleanBit::set(compiler_hints(), - kHasOnlySimpleThisPropertyAssignments, - only_simple_this_property_assignments)); - set_this_property_assignments(assignments); - set_this_property_assignments_count(assignments->length() / 3); -} - - -void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() { - Heap* heap = GetHeap(); - set_compiler_hints(BooleanBit::set(compiler_hints(), - kHasOnlySimpleThisPropertyAssignments, - false)); - set_this_property_assignments(heap->undefined_value()); - set_this_property_assignments_count(0); -} - - -String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) { - Object* obj = this_property_assignments(); - ASSERT(obj->IsFixedArray()); - ASSERT(index < this_property_assignments_count()); - obj = FixedArray::cast(obj)->get(index * 3); - ASSERT(obj->IsString()); - return String::cast(obj); -} - - -bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) { - Object* obj = this_property_assignments(); - ASSERT(obj->IsFixedArray()); - ASSERT(index < this_property_assignments_count()); - obj = FixedArray::cast(obj)->get(index * 3 + 1); - return Smi::cast(obj)->value() != -1; -} - - -int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) { - ASSERT(IsThisPropertyAssignmentArgument(index)); - Object* obj = - FixedArray::cast(this_property_assignments())->get(index * 3 + 1); - return Smi::cast(obj)->value(); -} - - -Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) { - ASSERT(!IsThisPropertyAssignmentArgument(index)); - Object* obj = - FixedArray::cast(this_property_assignments())->get(index * 3 + 2); - return obj; -} - - // Support function for printing the source code to a StringStream // without any allocation in the heap. void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator, diff --git a/src/objects.h b/src/objects.h index 11b231f..a16ebbf 100644 --- a/src/objects.h +++ b/src/objects.h @@ -6077,18 +6077,6 @@ class SharedFunctionInfo: public HeapObject { inline int ic_age(); inline void set_ic_age(int age); - // Add information on assignments of the form this.x = ...; - void SetThisPropertyAssignmentsInfo( - bool has_only_simple_this_property_assignments, - FixedArray* this_property_assignments); - - // Clear information on assignments of the form this.x = ...; - void ClearThisPropertyAssignmentsInfo(); - - // Indicate that this function only consists of assignments of the form - // this.x = y; where y is either a constant or refers to an argument. - inline bool has_only_simple_this_property_assignments(); - // Indicates if this function can be lazy compiled. // This is used to determine if we can safely flush code from a function // when doing GC if we expect that the function will no longer be used. @@ -6189,24 +6177,6 @@ class SharedFunctionInfo: public HeapObject { // disabled). bool VerifyBailoutId(BailoutId id); - // Check whether a inlined constructor can be generated with the given - // prototype. - bool CanGenerateInlineConstructor(Object* prototype); - - // Prevents further attempts to generate inline constructors. - // To be called if generation failed for any reason. - void ForbidInlineConstructor(); - - // For functions which only contains this property assignments this provides - // access to the names for the properties assigned. - DECL_ACCESSORS(this_property_assignments, Object) - inline int this_property_assignments_count(); - inline void set_this_property_assignments_count(int value); - String* GetThisPropertyAssignmentName(int index); - bool IsThisPropertyAssignmentArgument(int index); - int GetThisPropertyAssignmentArgument(int index); - Object* GetThisPropertyAssignmentConstant(int index); - // [source code]: Source code for the function. bool HasSourceCode(); Handle GetSourceCode(); @@ -6276,12 +6246,10 @@ class SharedFunctionInfo: public HeapObject { static const int kInferredNameOffset = kDebugInfoOffset + kPointerSize; static const int kInitialMapOffset = kInferredNameOffset + kPointerSize; - static const int kThisPropertyAssignmentsOffset = - kInitialMapOffset + kPointerSize; // ast_node_count is a Smi field. It could be grouped with another Smi field // into a PSEUDO_SMI_ACCESSORS pair (on x64), if one becomes available. static const int kAstNodeCountOffset = - kThisPropertyAssignmentsOffset + kPointerSize; + kInitialMapOffset + kPointerSize; #if V8_HOST_ARCH_32_BIT // Smi fields. static const int kLengthOffset = @@ -6299,10 +6267,7 @@ class SharedFunctionInfo: public HeapObject { kEndPositionOffset + kPointerSize; static const int kCompilerHintsOffset = kFunctionTokenPositionOffset + kPointerSize; - static const int kThisPropertyAssignmentsCountOffset = - kCompilerHintsOffset + kPointerSize; - static const int kOptCountOffset = - kThisPropertyAssignmentsCountOffset + kPointerSize; + static const int kOptCountOffset = kCompilerHintsOffset + kPointerSize; static const int kCountersOffset = kOptCountOffset + kPointerSize; static const int kStressDeoptCounterOffset = kCountersOffset + kPointerSize; @@ -6338,10 +6303,7 @@ class SharedFunctionInfo: public HeapObject { static const int kCompilerHintsOffset = kFunctionTokenPositionOffset + kIntSize; - static const int kThisPropertyAssignmentsCountOffset = - kCompilerHintsOffset + kIntSize; - static const int kOptCountOffset = - kThisPropertyAssignmentsCountOffset + kIntSize; + static const int kOptCountOffset = kCompilerHintsOffset + kIntSize; static const int kCountersOffset = kOptCountOffset + kIntSize; static const int kStressDeoptCounterOffset = kCountersOffset + kIntSize; @@ -6365,7 +6327,7 @@ class SharedFunctionInfo: public HeapObject { static const int kAlignedSize = POINTER_SIZE_ALIGN(kSize); typedef FixedBodyDescriptor BodyDescriptor; // Bit positions in start_position_and_type. @@ -6381,7 +6343,6 @@ class SharedFunctionInfo: public HeapObject { static const int kCodeAgeMask = (1 << kCodeAgeSize) - 1; enum CompilerHints { - kHasOnlySimpleThisPropertyAssignments, kAllowLazyCompilation, kAllowLazyCompilationWithoutContext, kLiveObjectsMayExist, diff --git a/src/parser.cc b/src/parser.cc index 9c55ad7..f032d97 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -490,8 +490,6 @@ Parser::FunctionState::FunctionState(Parser* parser, : next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize), next_handler_index_(0), expected_property_count_(0), - only_simple_this_property_assignments_(false), - this_property_assignments_(isolate->factory()->empty_fixed_array()), generator_object_variable_(NULL), parser_(parser), outer_function_state_(parser->current_function_state_), @@ -675,8 +673,6 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, function_state.materialized_literal_count(), function_state.expected_property_count(), function_state.handler_count(), - function_state.only_simple_this_property_assignments(), - function_state.this_property_assignments(), 0, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::ANONYMOUS_EXPRESSION, @@ -850,178 +846,6 @@ void Parser::ReportMessageAt(Scanner::Location source_location, } -// A ThisNamedPropertyAssignmentFinder finds and marks statements of the form -// this.x = ...;, where x is a named property. It also determines whether a -// function contains only assignments of this type. -class ThisNamedPropertyAssignmentFinder { - public: - ThisNamedPropertyAssignmentFinder(Isolate* isolate, Zone* zone) - : isolate_(isolate), - only_simple_this_property_assignments_(true), - names_(0, zone), - assigned_arguments_(0, zone), - assigned_constants_(0, zone), - zone_(zone) { - } - - static Assignment* AsAssignment(Statement* stat) { - if (stat == NULL) return NULL; - ExpressionStatement* exp_stat = stat->AsExpressionStatement(); - if (exp_stat == NULL) return NULL; - return exp_stat->expression()->AsAssignment(); - } - - void Update(Scope* scope, Statement* stat) { - // Bail out if function already has property assignment that are - // not simple this property assignments. - if (!only_simple_this_property_assignments_) { - return; - } - - // Check whether this statement is of the form this.x = ...; - Assignment* assignment = AsAssignment(stat); - if (IsThisPropertyAssignment(assignment)) { - HandleThisPropertyAssignment(scope, assignment); - } else { - only_simple_this_property_assignments_ = false; - } - } - - // Returns whether only statements of the form this.x = y; where y is either a - // constant or a function argument was encountered. - bool only_simple_this_property_assignments() { - return only_simple_this_property_assignments_; - } - - // Returns a fixed array containing three elements for each assignment of the - // form this.x = y; - Handle GetThisPropertyAssignments() { - if (names_.is_empty()) { - return isolate_->factory()->empty_fixed_array(); - } - ASSERT_EQ(names_.length(), assigned_arguments_.length()); - ASSERT_EQ(names_.length(), assigned_constants_.length()); - Handle assignments = - isolate_->factory()->NewFixedArray(names_.length() * 3); - for (int i = 0; i < names_.length(); ++i) { - assignments->set(i * 3, *names_[i]); - assignments->set(i * 3 + 1, Smi::FromInt(assigned_arguments_[i])); - assignments->set(i * 3 + 2, *assigned_constants_[i]); - } - return assignments; - } - - private: - bool IsThisPropertyAssignment(Assignment* assignment) { - if (assignment != NULL) { - Property* property = assignment->target()->AsProperty(); - return assignment->op() == Token::ASSIGN - && property != NULL - && property->obj()->AsVariableProxy() != NULL - && property->obj()->AsVariableProxy()->is_this(); - } - return false; - } - - void HandleThisPropertyAssignment(Scope* scope, Assignment* assignment) { - // Check that the property assigned to is a named property, which is not - // __proto__. - Property* property = assignment->target()->AsProperty(); - ASSERT(property != NULL); - Literal* literal = property->key()->AsLiteral(); - uint32_t dummy; - if (literal != NULL && - literal->handle()->IsString() && - !String::cast(*(literal->handle()))->Equals( - isolate_->heap()->proto_string()) && - !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) { - Handle key = Handle::cast(literal->handle()); - - // Check whether the value assigned is either a constant or matches the - // name of one of the arguments to the function. - if (assignment->value()->AsLiteral() != NULL) { - // Constant assigned. - Literal* literal = assignment->value()->AsLiteral(); - AssignmentFromConstant(key, literal->handle()); - return; - } else if (assignment->value()->AsVariableProxy() != NULL) { - // Variable assigned. - Handle name = - assignment->value()->AsVariableProxy()->name(); - // Check whether the variable assigned matches an argument name. - for (int i = 0; i < scope->num_parameters(); i++) { - if (*scope->parameter(i)->name() == *name) { - // Assigned from function argument. - AssignmentFromParameter(key, i); - return; - } - } - } - } - // It is not a simple "this.x = value;" assignment with a constant - // or parameter value. - AssignmentFromSomethingElse(); - } - - - - - // We will potentially reorder the property assignments, so they must be - // simple enough that the ordering does not matter. - void AssignmentFromParameter(Handle name, int index) { - EnsureInitialized(); - for (int i = 0; i < names_.length(); ++i) { - if (name->Equals(*names_[i])) { - assigned_arguments_[i] = index; - assigned_constants_[i] = isolate_->factory()->undefined_value(); - return; - } - } - names_.Add(name, zone()); - assigned_arguments_.Add(index, zone()); - assigned_constants_.Add(isolate_->factory()->undefined_value(), zone()); - } - - void AssignmentFromConstant(Handle name, Handle value) { - EnsureInitialized(); - for (int i = 0; i < names_.length(); ++i) { - if (name->Equals(*names_[i])) { - assigned_arguments_[i] = -1; - assigned_constants_[i] = value; - return; - } - } - names_.Add(name, zone()); - assigned_arguments_.Add(-1, zone()); - assigned_constants_.Add(value, zone()); - } - - void AssignmentFromSomethingElse() { - // The this assignment is not a simple one. - only_simple_this_property_assignments_ = false; - } - - void EnsureInitialized() { - if (names_.capacity() == 0) { - ASSERT(assigned_arguments_.capacity() == 0); - ASSERT(assigned_constants_.capacity() == 0); - names_.Initialize(4, zone()); - assigned_arguments_.Initialize(4, zone()); - assigned_constants_.Initialize(4, zone()); - } - } - - Zone* zone() const { return zone_; } - - Isolate* isolate_; - bool only_simple_this_property_assignments_; - ZoneStringList names_; - ZoneList assigned_arguments_; - ZoneObjectList assigned_constants_; - Zone* zone_; -}; - - void* Parser::ParseSourceElements(ZoneList* processor, int end_token, bool is_eval, @@ -1037,8 +861,6 @@ void* Parser::ParseSourceElements(ZoneList* processor, TargetScope scope(&this->target_stack_); ASSERT(processor != NULL); - ThisNamedPropertyAssignmentFinder this_property_assignment_finder(isolate(), - zone()); bool directive_prologue = true; // Parsing directive prologue. while (peek() != end_token) { @@ -1098,25 +920,9 @@ void* Parser::ParseSourceElements(ZoneList* processor, } } - // Find and mark all assignments to named properties in this (this.x =) - if (top_scope_->is_function_scope()) { - this_property_assignment_finder.Update(top_scope_, stat); - } processor->Add(stat, zone()); } - // Propagate the collected information on this property assignments. - if (top_scope_->is_function_scope()) { - bool only_simple_this_property_assignments = - this_property_assignment_finder.only_simple_this_property_assignments() - && top_scope_->declarations()->length() == 0; - if (only_simple_this_property_assignments) { - current_function_state_->SetThisPropertyAssignmentInfo( - only_simple_this_property_assignments, - this_property_assignment_finder.GetThisPropertyAssignments()); - } - } - return 0; } @@ -4387,8 +4193,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle function_name, int materialized_literal_count = -1; int expected_property_count = -1; int handler_count = 0; - bool only_simple_this_property_assignments; - Handle this_property_assignments; FunctionLiteral::ParameterFlag duplicate_parameters = FunctionLiteral::kNoDuplicateParameters; FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_ @@ -4519,8 +4323,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle function_name, materialized_literal_count = entry.literal_count(); expected_property_count = entry.property_count(); top_scope_->SetLanguageMode(entry.language_mode()); - only_simple_this_property_assignments = false; - this_property_assignments = isolate()->factory()->empty_fixed_array(); } else { is_lazily_compiled = false; } @@ -4555,8 +4357,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle function_name, materialized_literal_count = logger.literals(); expected_property_count = logger.properties(); top_scope_->SetLanguageMode(logger.language_mode()); - only_simple_this_property_assignments = false; - this_property_assignments = isolate()->factory()->empty_fixed_array(); } } @@ -4609,9 +4409,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle function_name, materialized_literal_count = function_state.materialized_literal_count(); expected_property_count = function_state.expected_property_count(); handler_count = function_state.handler_count(); - only_simple_this_property_assignments = - function_state.only_simple_this_property_assignments(); - this_property_assignments = function_state.this_property_assignments(); Expect(Token::RBRACE, CHECK_OK); scope->set_end_position(scanner().location().end_pos); @@ -4677,8 +4474,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle function_name, materialized_literal_count, expected_property_count, handler_count, - only_simple_this_property_assignments, - this_property_assignments, num_parameters, duplicate_parameters, type, diff --git a/src/parser.h b/src/parser.h index 8a3ae92..ed9ee10 100644 --- a/src/parser.h +++ b/src/parser.h @@ -501,20 +501,6 @@ class Parser BASE_EMBEDDED { int NextHandlerIndex() { return next_handler_index_++; } int handler_count() { return next_handler_index_; } - void SetThisPropertyAssignmentInfo( - bool only_simple_this_property_assignments, - Handle this_property_assignments) { - only_simple_this_property_assignments_ = - only_simple_this_property_assignments; - this_property_assignments_ = this_property_assignments; - } - bool only_simple_this_property_assignments() { - return only_simple_this_property_assignments_; - } - Handle this_property_assignments() { - return this_property_assignments_; - } - void AddProperty() { expected_property_count_++; } int expected_property_count() { return expected_property_count_; } @@ -544,11 +530,6 @@ class Parser BASE_EMBEDDED { // Properties count estimation. int expected_property_count_; - // Keeps track of assignments to properties of this. Used for - // optimizing constructors. - bool only_simple_this_property_assignments_; - Handle this_property_assignments_; - // For generators, the variable that holds the generator object. This // variable is used by yield expressions and return statements. NULL // indicates that this function is not a generator. diff --git a/src/runtime.cc b/src/runtime.cc index c47e35d..f8147a2 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -2513,10 +2513,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { // Since we don't store the source we should never optimize this. target_shared->code()->set_optimizable(false); - // Clear the optimization hints related to the compiled code as these - // are no longer valid when the code is overwritten. - target_shared->ClearThisPropertyAssignmentsInfo(); - // Set the code of the target function. target->ReplaceCode(source_shared->code()); ASSERT(target->next_function_link()->IsUndefined()); diff --git a/src/stub-cache.cc b/src/stub-cache.cc index d100e61..76eb076 100644 --- a/src/stub-cache.cc +++ b/src/stub-cache.cc @@ -2029,15 +2029,6 @@ Handle CallStubCompiler::GetCode(Handle function) { } -Handle ConstructStubCompiler::GetCode() { - Code::Flags flags = Code::ComputeFlags(Code::STUB); - Handle code = GetCodeWithFlags(flags, "ConstructStub"); - PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, "ConstructStub")); - GDBJIT(AddCode(GDBJITInterface::STUB, "ConstructStub", *code)); - return code; -} - - CallOptimization::CallOptimization(LookupResult* lookup) { if (lookup->IsFound() && lookup->IsCacheable() && diff --git a/src/stub-cache.h b/src/stub-cache.h index 9365d96..a1b55d8 100644 --- a/src/stub-cache.h +++ b/src/stub-cache.h @@ -1067,17 +1067,6 @@ class CallStubCompiler: public StubCompiler { }; -class ConstructStubCompiler: public StubCompiler { - public: - explicit ConstructStubCompiler(Isolate* isolate) : StubCompiler(isolate) { } - - Handle CompileConstructStub(Handle function); - - private: - Handle GetCode(); -}; - - // Holds information about possible function call optimizations. class CallOptimization BASE_EMBEDDED { public: diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index c1cab8f..bc3df68 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -2961,139 +2961,6 @@ Handle BaseLoadStubCompiler::CompilePolymorphicIC( } -// Specialized stub for constructing objects from functions which only have only -// simple assignments of the form this.x = ...; in their body. -Handle ConstructStubCompiler::CompileConstructStub( - Handle function) { - // ----------- S t a t e ------------- - // -- rax : argc - // -- rdi : constructor - // -- rsp[0] : return address - // -- rsp[4] : last argument - // ----------------------------------- - Label generic_stub_call; - - // Use r8 for holding undefined which is used in several places below. - __ Move(r8, factory()->undefined_value()); - -#ifdef ENABLE_DEBUGGER_SUPPORT - // Check to see whether there are any break points in the function code. If - // there are jump to the generic constructor stub which calls the actual - // code for the function thereby hitting the break points. - __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); - __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kDebugInfoOffset)); - __ cmpq(rbx, r8); - __ j(not_equal, &generic_stub_call); -#endif - - // Load the initial map and verify that it is in fact a map. - // rdi: constructor - __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); - // Will both indicate a NULL and a Smi. - STATIC_ASSERT(kSmiTag == 0); - __ JumpIfSmi(rbx, &generic_stub_call); - __ CmpObjectType(rbx, MAP_TYPE, rcx); - __ j(not_equal, &generic_stub_call); - -#ifdef DEBUG - // Cannot construct functions this way. - // rbx: initial map - __ CmpInstanceType(rbx, JS_FUNCTION_TYPE); - __ Check(not_equal, "Function constructed by construct stub."); -#endif - - // Now allocate the JSObject in new space. - // rbx: initial map - ASSERT(function->has_initial_map()); - int instance_size = function->initial_map()->instance_size(); -#ifdef DEBUG - __ movzxbq(rcx, FieldOperand(rbx, Map::kInstanceSizeOffset)); - __ shl(rcx, Immediate(kPointerSizeLog2)); - __ cmpq(rcx, Immediate(instance_size)); - __ Check(equal, "Instance size of initial map changed."); -#endif - __ Allocate(instance_size, rdx, rcx, no_reg, &generic_stub_call, - NO_ALLOCATION_FLAGS); - - // Allocated the JSObject, now initialize the fields and add the heap tag. - // rbx: initial map - // rdx: JSObject (untagged) - __ movq(Operand(rdx, JSObject::kMapOffset), rbx); - __ Move(rbx, factory()->empty_fixed_array()); - __ movq(Operand(rdx, JSObject::kPropertiesOffset), rbx); - __ movq(Operand(rdx, JSObject::kElementsOffset), rbx); - - // rax: argc - // rdx: JSObject (untagged) - // Load the address of the first in-object property into r9. - __ lea(r9, Operand(rdx, JSObject::kHeaderSize)); - // Calculate the location of the first argument. The stack contains only the - // return address on top of the argc arguments. - __ lea(rcx, Operand(rsp, rax, times_pointer_size, 0)); - - // rax: argc - // rcx: first argument - // rdx: JSObject (untagged) - // r8: undefined - // r9: first in-object property of the JSObject - // Fill the initialized properties with a constant value or a passed argument - // depending on the this.x = ...; assignment in the function. - Handle shared(function->shared()); - for (int i = 0; i < shared->this_property_assignments_count(); i++) { - if (shared->IsThisPropertyAssignmentArgument(i)) { - // Check if the argument assigned to the property is actually passed. - // If argument is not passed the property is set to undefined, - // otherwise find it on the stack. - int arg_number = shared->GetThisPropertyAssignmentArgument(i); - __ movq(rbx, r8); - __ cmpq(rax, Immediate(arg_number)); - __ cmovq(above, rbx, Operand(rcx, arg_number * -kPointerSize)); - // Store value in the property. - __ movq(Operand(r9, i * kPointerSize), rbx); - } else { - // Set the property to the constant value. - Handle constant(shared->GetThisPropertyAssignmentConstant(i), - isolate()); - __ Move(Operand(r9, i * kPointerSize), constant); - } - } - - // Fill the unused in-object property fields with undefined. - for (int i = shared->this_property_assignments_count(); - i < function->initial_map()->inobject_properties(); - i++) { - __ movq(Operand(r9, i * kPointerSize), r8); - } - - // rax: argc - // rdx: JSObject (untagged) - // Move argc to rbx and the JSObject to return to rax and tag it. - __ movq(rbx, rax); - __ movq(rax, rdx); - __ or_(rax, Immediate(kHeapObjectTag)); - - // rax: JSObject - // rbx: argc - // Remove caller arguments and receiver from the stack and return. - __ pop(rcx); - __ lea(rsp, Operand(rsp, rbx, times_pointer_size, 1 * kPointerSize)); - __ push(rcx); - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->constructed_objects(), 1); - __ IncrementCounter(counters->constructed_objects_stub(), 1); - __ ret(0); - - // Jump to the generic stub in case the specialized code cannot handle the - // construction. - __ bind(&generic_stub_call); - Handle code = isolate()->builtins()->JSConstructStubGeneric(); - __ Jump(code, RelocInfo::CODE_TARGET); - - // Return the generated code. - return GetCode(); -} - - #undef __ #define __ ACCESS_MASM(masm) diff --git a/test/mjsunit/bugs/bug-618.js b/test/mjsunit/bugs/bug-618.js deleted file mode 100644 index 0513f87..0000000 --- a/test/mjsunit/bugs/bug-618.js +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// When this bug is corrected move to object-define-property and add -// additional tests for configurable in the same manner as existing tests -// there. - -function C() { - this.x = 23; -} - -// If a setter is added to the prototype chain of a simple constructor setting -// one of the properties assigned in the constructor then this setter is -// ignored when constructing new objects from the constructor. - -// This only happens if the setter is added _after_ an instance has been -// created. - -assertEquals(23, new C().x); -C.prototype.__defineSetter__('x', function(value) { this.y = 23; }); -assertEquals(void 0, new C().x); diff --git a/test/mjsunit/object-define-property.js b/test/mjsunit/object-define-property.js index 835d0e0..cbb2d21 100644 --- a/test/mjsunit/object-define-property.js +++ b/test/mjsunit/object-define-property.js @@ -1195,3 +1195,12 @@ Assign(new C); %OptimizeFunctionOnNextCall(Assign); Object.defineProperty(C.prototype, "blubb", {get: function() { return -42; }}); Assign(new C); + +// Test that changes to the prototype of a simple constructor are not ignored, +// even after creating initial instances. +function C() { + this.x = 23; +} +assertEquals(23, new C().x); +C.prototype.__defineSetter__('x', function(value) { this.y = 23; }); +assertEquals(void 0, new C().x); diff --git a/test/mjsunit/bugs/618.js b/test/mjsunit/regress/regress-618.js similarity index 100% rename from test/mjsunit/bugs/618.js rename to test/mjsunit/regress/regress-618.js