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
This commit is contained in:
verwaest@chromium.org 2013-06-05 08:43:25 +00:00
parent 40a5fc747d
commit 5e8679beea
20 changed files with 23 additions and 1125 deletions

View File

@ -3091,151 +3091,6 @@ Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
}
Handle<Code> ConstructStubCompiler::CompileConstructStub(
Handle<JSFunction> 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<SharedFunctionInfo> 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, &not_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(&not_passed);
// Set the property to undefined.
__ str(r7, MemOperand(r5, kPointerSize, PostIndex));
__ bind(&next);
} else {
// Set the property to the constant value.
Handle<Object> 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> code = isolate()->builtins()->JSConstructStubGeneric();
__ Jump(code, RelocInfo::CODE_TARGET);
// Return the generated code.
return GetCode();
}
#undef __
#define __ ACCESS_MASM(masm)

View File

@ -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<FixedArray> 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<FixedArray> 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<String> name_;
Scope* scope_;
ZoneList<Statement*>* body_;
Handle<FixedArray> this_property_assignments_;
Handle<String> inferred_name_;
AstProperties ast_properties_;
@ -2267,14 +2255,13 @@ class FunctionLiteral: public Expression {
int function_token_position_;
unsigned bitfield_;
class HasOnlySimpleThisPropertyAssignments: public BitField<bool, 0, 1> {};
class IsExpression: public BitField<bool, 1, 1> {};
class IsAnonymous: public BitField<bool, 2, 1> {};
class Pretenure: public BitField<bool, 3, 1> {};
class HasDuplicateParameters: public BitField<ParameterFlag, 4, 1> {};
class IsFunction: public BitField<IsFunctionFlag, 5, 1> {};
class IsParenthesized: public BitField<IsParenthesizedFlag, 6, 1> {};
class IsGenerator: public BitField<IsGeneratorFlag, 7, 1> {};
class IsExpression: public BitField<bool, 0, 1> {};
class IsAnonymous: public BitField<bool, 1, 1> {};
class Pretenure: public BitField<bool, 2, 1> {};
class HasDuplicateParameters: public BitField<ParameterFlag, 3, 1> {};
class IsFunction: public BitField<IsFunctionFlag, 4, 1> {};
class IsParenthesized: public BitField<IsParenthesizedFlag, 5, 1> {};
class IsGenerator: public BitField<IsGeneratorFlag, 6, 1> {};
};
@ -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<FixedArray> 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.

View File

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

View File

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

View File

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

View File

@ -3178,145 +3178,6 @@ Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
}
// Specialized stub for constructing objects from functions which only have only
// simple assignments of the form this.x = ...; in their body.
Handle<Code> ConstructStubCompiler::CompileConstructStub(
Handle<JSFunction> 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<SharedFunctionInfo> 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, &not_passed);
__ mov(ebx, Operand(ecx, arg_number * -kPointerSize));
__ bind(&not_passed);
}
// Store value in the property.
__ mov(Operand(edx, i * kPointerSize), ebx);
} else {
// Set the property to the constant value.
Handle<Object> 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> code = isolate()->builtins()->JSConstructStubGeneric();
__ jmp(code, RelocInfo::CODE_TARGET);
// Return the generated code.
return GetCode();
}
#undef __
#define __ ACCESS_MASM(masm)

View File

@ -3143,157 +3143,6 @@ Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
}
Handle<Code> ConstructStubCompiler::CompileConstructStub(
Handle<JSFunction> 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<SharedFunctionInfo> 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(&not_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(&not_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<Object> 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<Code> generic_construct_stub =
isolate()->builtins()->JSConstructStubGeneric();
__ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
// Return the generated code.
return GetCode();
}
#undef __
#define __ ACCESS_MASM(masm)

View File

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

View File

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

View File

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

View File

@ -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<Object> 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<kNameOffset,
kThisPropertyAssignmentsOffset + kPointerSize,
kInitialMapOffset + kPointerSize,
kSize> 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,

View File

@ -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<FixedArray> 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<FixedArray> 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<String> key = Handle<String>::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<String> 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<String> 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<String> name, Handle<Object> 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<int> assigned_arguments_;
ZoneObjectList assigned_constants_;
Zone* zone_;
};
void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
int end_token,
bool is_eval,
@ -1037,8 +861,6 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* 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<Statement*>* 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<String> function_name,
int materialized_literal_count = -1;
int expected_property_count = -1;
int handler_count = 0;
bool only_simple_this_property_assignments;
Handle<FixedArray> this_property_assignments;
FunctionLiteral::ParameterFlag duplicate_parameters =
FunctionLiteral::kNoDuplicateParameters;
FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_
@ -4519,8 +4323,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> 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<String> 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<String> 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<String> function_name,
materialized_literal_count,
expected_property_count,
handler_count,
only_simple_this_property_assignments,
this_property_assignments,
num_parameters,
duplicate_parameters,
type,

View File

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

View File

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

View File

@ -2029,15 +2029,6 @@ Handle<Code> CallStubCompiler::GetCode(Handle<JSFunction> function) {
}
Handle<Code> ConstructStubCompiler::GetCode() {
Code::Flags flags = Code::ComputeFlags(Code::STUB);
Handle<Code> 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() &&

View File

@ -1067,17 +1067,6 @@ class CallStubCompiler: public StubCompiler {
};
class ConstructStubCompiler: public StubCompiler {
public:
explicit ConstructStubCompiler(Isolate* isolate) : StubCompiler(isolate) { }
Handle<Code> CompileConstructStub(Handle<JSFunction> function);
private:
Handle<Code> GetCode();
};
// Holds information about possible function call optimizations.
class CallOptimization BASE_EMBEDDED {
public:

View File

@ -2961,139 +2961,6 @@ Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
}
// Specialized stub for constructing objects from functions which only have only
// simple assignments of the form this.x = ...; in their body.
Handle<Code> ConstructStubCompiler::CompileConstructStub(
Handle<JSFunction> 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<SharedFunctionInfo> 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<Object> 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> code = isolate()->builtins()->JSConstructStubGeneric();
__ Jump(code, RelocInfo::CODE_TARGET);
// Return the generated code.
return GetCode();
}
#undef __
#define __ ACCESS_MASM(masm)

View File

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

View File

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