Handlify Map::CopyDropDescriptors().
* And contain knowledge better in TransitionArray and DescriptorArray (for example WhitenessWitness is now private to DescriptorArray). * And remove some factory methods * And handlify some other things. R=verwaest@chromium.org Review URL: https://codereview.chromium.org/234783002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20686 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
93c9717473
commit
c5eaf80707
@ -383,8 +383,7 @@ static Handle<JSFunction> InstallFunction(Handle<JSObject> target,
|
||||
void Genesis::SetFunctionInstanceDescriptor(
|
||||
Handle<Map> map, PrototypePropertyMode prototypeMode) {
|
||||
int size = (prototypeMode == DONT_ADD_PROTOTYPE) ? 4 : 5;
|
||||
Handle<DescriptorArray> descriptors(factory()->NewDescriptorArray(0, size));
|
||||
DescriptorArray::WhitenessWitness witness(*descriptors);
|
||||
Map::EnsureDescriptorSlack(map, size);
|
||||
|
||||
Handle<Foreign> length(factory()->NewForeign(&Accessors::FunctionLength));
|
||||
Handle<Foreign> name(factory()->NewForeign(&Accessors::FunctionName));
|
||||
@ -396,23 +395,22 @@ void Genesis::SetFunctionInstanceDescriptor(
|
||||
}
|
||||
PropertyAttributes attribs = static_cast<PropertyAttributes>(
|
||||
DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
map->set_instance_descriptors(*descriptors);
|
||||
|
||||
{ // Add length.
|
||||
CallbacksDescriptor d(factory()->length_string(), length, attribs);
|
||||
map->AppendDescriptor(&d, witness);
|
||||
map->AppendDescriptor(&d);
|
||||
}
|
||||
{ // Add name.
|
||||
CallbacksDescriptor d(factory()->name_string(), name, attribs);
|
||||
map->AppendDescriptor(&d, witness);
|
||||
map->AppendDescriptor(&d);
|
||||
}
|
||||
{ // Add arguments.
|
||||
CallbacksDescriptor d(factory()->arguments_string(), args, attribs);
|
||||
map->AppendDescriptor(&d, witness);
|
||||
map->AppendDescriptor(&d);
|
||||
}
|
||||
{ // Add caller.
|
||||
CallbacksDescriptor d(factory()->caller_string(), caller, attribs);
|
||||
map->AppendDescriptor(&d, witness);
|
||||
map->AppendDescriptor(&d);
|
||||
}
|
||||
if (prototypeMode != DONT_ADD_PROTOTYPE) {
|
||||
// Add prototype.
|
||||
@ -420,7 +418,7 @@ void Genesis::SetFunctionInstanceDescriptor(
|
||||
attribs = static_cast<PropertyAttributes>(attribs & ~READ_ONLY);
|
||||
}
|
||||
CallbacksDescriptor d(factory()->prototype_string(), prototype, attribs);
|
||||
map->AppendDescriptor(&d, witness);
|
||||
map->AppendDescriptor(&d);
|
||||
}
|
||||
}
|
||||
|
||||
@ -522,8 +520,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
|
||||
void Genesis::SetStrictFunctionInstanceDescriptor(
|
||||
Handle<Map> map, PrototypePropertyMode prototypeMode) {
|
||||
int size = (prototypeMode == DONT_ADD_PROTOTYPE) ? 4 : 5;
|
||||
Handle<DescriptorArray> descriptors(factory()->NewDescriptorArray(0, size));
|
||||
DescriptorArray::WhitenessWitness witness(*descriptors);
|
||||
Map::EnsureDescriptorSlack(map, size);
|
||||
|
||||
Handle<Foreign> length(factory()->NewForeign(&Accessors::FunctionLength));
|
||||
Handle<Foreign> name(factory()->NewForeign(&Accessors::FunctionName));
|
||||
@ -537,31 +534,30 @@ void Genesis::SetStrictFunctionInstanceDescriptor(
|
||||
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
|
||||
PropertyAttributes ro_attribs =
|
||||
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
map->set_instance_descriptors(*descriptors);
|
||||
|
||||
{ // Add length.
|
||||
CallbacksDescriptor d(factory()->length_string(), length, ro_attribs);
|
||||
map->AppendDescriptor(&d, witness);
|
||||
map->AppendDescriptor(&d);
|
||||
}
|
||||
{ // Add name.
|
||||
CallbacksDescriptor d(factory()->name_string(), name, ro_attribs);
|
||||
map->AppendDescriptor(&d, witness);
|
||||
map->AppendDescriptor(&d);
|
||||
}
|
||||
{ // Add arguments.
|
||||
CallbacksDescriptor d(factory()->arguments_string(), arguments,
|
||||
rw_attribs);
|
||||
map->AppendDescriptor(&d, witness);
|
||||
map->AppendDescriptor(&d);
|
||||
}
|
||||
{ // Add caller.
|
||||
CallbacksDescriptor d(factory()->caller_string(), caller, rw_attribs);
|
||||
map->AppendDescriptor(&d, witness);
|
||||
map->AppendDescriptor(&d);
|
||||
}
|
||||
if (prototypeMode != DONT_ADD_PROTOTYPE) {
|
||||
// Add prototype.
|
||||
PropertyAttributes attribs =
|
||||
prototypeMode == ADD_WRITEABLE_PROTOTYPE ? rw_attribs : ro_attribs;
|
||||
CallbacksDescriptor d(factory()->prototype_string(), prototype, attribs);
|
||||
map->AppendDescriptor(&d, witness);
|
||||
map->AppendDescriptor(&d);
|
||||
}
|
||||
}
|
||||
|
||||
@ -861,19 +857,15 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
|
||||
// This assert protects an optimization in
|
||||
// HGraphBuilder::JSArrayBuilder::EmitMapCode()
|
||||
ASSERT(initial_map->elements_kind() == GetInitialFastElementsKind());
|
||||
|
||||
Handle<DescriptorArray> array_descriptors(
|
||||
factory->NewDescriptorArray(0, 1));
|
||||
DescriptorArray::WhitenessWitness witness(*array_descriptors);
|
||||
Map::EnsureDescriptorSlack(initial_map, 1);
|
||||
|
||||
Handle<Foreign> array_length(factory->NewForeign(&Accessors::ArrayLength));
|
||||
PropertyAttributes attribs = static_cast<PropertyAttributes>(
|
||||
DONT_ENUM | DONT_DELETE);
|
||||
initial_map->set_instance_descriptors(*array_descriptors);
|
||||
|
||||
{ // Add length.
|
||||
CallbacksDescriptor d(factory->length_string(), array_length, attribs);
|
||||
array_function->initial_map()->AppendDescriptor(&d, witness);
|
||||
array_function->initial_map()->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
// array_function is used internally. JS code creating array object should
|
||||
@ -916,19 +908,16 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
|
||||
|
||||
Handle<Map> string_map =
|
||||
Handle<Map>(native_context()->string_function()->initial_map());
|
||||
Handle<DescriptorArray> string_descriptors(
|
||||
factory->NewDescriptorArray(0, 1));
|
||||
DescriptorArray::WhitenessWitness witness(*string_descriptors);
|
||||
Map::EnsureDescriptorSlack(string_map, 1);
|
||||
|
||||
Handle<Foreign> string_length(
|
||||
factory->NewForeign(&Accessors::StringLength));
|
||||
PropertyAttributes attribs = static_cast<PropertyAttributes>(
|
||||
DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
string_map->set_instance_descriptors(*string_descriptors);
|
||||
|
||||
{ // Add length.
|
||||
CallbacksDescriptor d(factory->length_string(), string_length, attribs);
|
||||
string_map->AppendDescriptor(&d, witness);
|
||||
string_map->AppendDescriptor(&d);
|
||||
}
|
||||
}
|
||||
|
||||
@ -958,9 +947,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
|
||||
|
||||
PropertyAttributes final =
|
||||
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(0, 5);
|
||||
DescriptorArray::WhitenessWitness witness(*descriptors);
|
||||
initial_map->set_instance_descriptors(*descriptors);
|
||||
Map::EnsureDescriptorSlack(initial_map, 5);
|
||||
|
||||
{
|
||||
// ECMA-262, section 15.10.7.1.
|
||||
@ -968,7 +955,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
|
||||
JSRegExp::kSourceFieldIndex,
|
||||
final,
|
||||
Representation::Tagged());
|
||||
initial_map->AppendDescriptor(&field, witness);
|
||||
initial_map->AppendDescriptor(&field);
|
||||
}
|
||||
{
|
||||
// ECMA-262, section 15.10.7.2.
|
||||
@ -976,7 +963,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
|
||||
JSRegExp::kGlobalFieldIndex,
|
||||
final,
|
||||
Representation::Tagged());
|
||||
initial_map->AppendDescriptor(&field, witness);
|
||||
initial_map->AppendDescriptor(&field);
|
||||
}
|
||||
{
|
||||
// ECMA-262, section 15.10.7.3.
|
||||
@ -984,7 +971,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
|
||||
JSRegExp::kIgnoreCaseFieldIndex,
|
||||
final,
|
||||
Representation::Tagged());
|
||||
initial_map->AppendDescriptor(&field, witness);
|
||||
initial_map->AppendDescriptor(&field);
|
||||
}
|
||||
{
|
||||
// ECMA-262, section 15.10.7.4.
|
||||
@ -992,7 +979,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
|
||||
JSRegExp::kMultilineFieldIndex,
|
||||
final,
|
||||
Representation::Tagged());
|
||||
initial_map->AppendDescriptor(&field, witness);
|
||||
initial_map->AppendDescriptor(&field);
|
||||
}
|
||||
{
|
||||
// ECMA-262, section 15.10.7.5.
|
||||
@ -1002,7 +989,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
|
||||
JSRegExp::kLastIndexFieldIndex,
|
||||
writable,
|
||||
Representation::Tagged());
|
||||
initial_map->AppendDescriptor(&field, witness);
|
||||
initial_map->AppendDescriptor(&field);
|
||||
}
|
||||
|
||||
initial_map->set_inobject_properties(5);
|
||||
@ -1175,26 +1162,24 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
|
||||
Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE,
|
||||
Heap::kStrictArgumentsObjectSize);
|
||||
// Create the descriptor array for the arguments object.
|
||||
Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(0, 3);
|
||||
DescriptorArray::WhitenessWitness witness(*descriptors);
|
||||
map->set_instance_descriptors(*descriptors);
|
||||
Map::EnsureDescriptorSlack(map, 3);
|
||||
|
||||
{ // length
|
||||
FieldDescriptor d(
|
||||
factory->length_string(), 0, DONT_ENUM, Representation::Tagged());
|
||||
map->AppendDescriptor(&d, witness);
|
||||
map->AppendDescriptor(&d);
|
||||
}
|
||||
{ // callee
|
||||
CallbacksDescriptor d(factory->callee_string(),
|
||||
callee,
|
||||
attributes);
|
||||
map->AppendDescriptor(&d, witness);
|
||||
map->AppendDescriptor(&d);
|
||||
}
|
||||
{ // caller
|
||||
CallbacksDescriptor d(factory->caller_string(),
|
||||
caller,
|
||||
attributes);
|
||||
map->AppendDescriptor(&d, witness);
|
||||
map->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
map->set_function_with_prototype(true);
|
||||
@ -1380,11 +1365,8 @@ void Genesis::InitializeExperimentalGlobal() {
|
||||
object_function, JSGeneratorObject::kResultPropertyCount);
|
||||
ASSERT(generator_result_map->inobject_properties() ==
|
||||
JSGeneratorObject::kResultPropertyCount);
|
||||
|
||||
Handle<DescriptorArray> descriptors = factory()->NewDescriptorArray(0,
|
||||
JSGeneratorObject::kResultPropertyCount);
|
||||
DescriptorArray::WhitenessWitness witness(*descriptors);
|
||||
generator_result_map->set_instance_descriptors(*descriptors);
|
||||
Map::EnsureDescriptorSlack(
|
||||
generator_result_map, JSGeneratorObject::kResultPropertyCount);
|
||||
|
||||
Handle<String> value_string = factory()->InternalizeOneByteString(
|
||||
STATIC_ASCII_VECTOR("value"));
|
||||
@ -1392,7 +1374,7 @@ void Genesis::InitializeExperimentalGlobal() {
|
||||
JSGeneratorObject::kResultValuePropertyIndex,
|
||||
NONE,
|
||||
Representation::Tagged());
|
||||
generator_result_map->AppendDescriptor(&value_descr, witness);
|
||||
generator_result_map->AppendDescriptor(&value_descr);
|
||||
|
||||
Handle<String> done_string = factory()->InternalizeOneByteString(
|
||||
STATIC_ASCII_VECTOR("done"));
|
||||
@ -1400,7 +1382,7 @@ void Genesis::InitializeExperimentalGlobal() {
|
||||
JSGeneratorObject::kResultDonePropertyIndex,
|
||||
NONE,
|
||||
Representation::Tagged());
|
||||
generator_result_map->AppendDescriptor(&done_descr, witness);
|
||||
generator_result_map->AppendDescriptor(&done_descr);
|
||||
|
||||
generator_result_map->set_unused_property_fields(0);
|
||||
ASSERT_EQ(JSGeneratorObject::kResultSize,
|
||||
@ -1606,20 +1588,17 @@ Handle<JSFunction> Genesis::InstallInternalArray(
|
||||
array_function->set_initial_map(*initial_map);
|
||||
|
||||
// Make "length" magic on instances.
|
||||
Handle<DescriptorArray> array_descriptors(
|
||||
factory()->NewDescriptorArray(0, 1));
|
||||
DescriptorArray::WhitenessWitness witness(*array_descriptors);
|
||||
Map::EnsureDescriptorSlack(initial_map, 1);
|
||||
|
||||
Handle<Foreign> array_length(factory()->NewForeign(
|
||||
&Accessors::ArrayLength));
|
||||
PropertyAttributes attribs = static_cast<PropertyAttributes>(
|
||||
DONT_ENUM | DONT_DELETE);
|
||||
initial_map->set_instance_descriptors(*array_descriptors);
|
||||
|
||||
{ // Add length.
|
||||
CallbacksDescriptor d(
|
||||
factory()->length_string(), array_length, attribs);
|
||||
array_function->initial_map()->AppendDescriptor(&d, witness);
|
||||
array_function->initial_map()->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
return array_function;
|
||||
@ -1700,10 +1679,7 @@ bool Genesis::InstallNatives() {
|
||||
native_context()->set_script_function(*script_fun);
|
||||
|
||||
Handle<Map> script_map = Handle<Map>(script_fun->initial_map());
|
||||
|
||||
Handle<DescriptorArray> script_descriptors(
|
||||
factory()->NewDescriptorArray(0, 13));
|
||||
DescriptorArray::WhitenessWitness witness(*script_descriptors);
|
||||
Map::EnsureDescriptorSlack(script_map, 13);
|
||||
|
||||
Handle<Foreign> script_source(
|
||||
factory()->NewForeign(&Accessors::ScriptSource));
|
||||
@ -1755,61 +1731,60 @@ bool Genesis::InstallNatives() {
|
||||
factory()->NewForeign(&Accessors::ScriptEvalFromFunctionName));
|
||||
PropertyAttributes attribs =
|
||||
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
script_map->set_instance_descriptors(*script_descriptors);
|
||||
|
||||
{
|
||||
CallbacksDescriptor d(
|
||||
factory()->source_string(), script_source, attribs);
|
||||
script_map->AppendDescriptor(&d, witness);
|
||||
script_map->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
{
|
||||
CallbacksDescriptor d(factory()->name_string(), script_name, attribs);
|
||||
script_map->AppendDescriptor(&d, witness);
|
||||
script_map->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
{
|
||||
CallbacksDescriptor d(id_string, script_id, attribs);
|
||||
script_map->AppendDescriptor(&d, witness);
|
||||
script_map->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
{
|
||||
CallbacksDescriptor d(line_offset_string, script_line_offset, attribs);
|
||||
script_map->AppendDescriptor(&d, witness);
|
||||
script_map->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
{
|
||||
CallbacksDescriptor d(
|
||||
column_offset_string, script_column_offset, attribs);
|
||||
script_map->AppendDescriptor(&d, witness);
|
||||
script_map->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
{
|
||||
CallbacksDescriptor d(type_string, script_type, attribs);
|
||||
script_map->AppendDescriptor(&d, witness);
|
||||
script_map->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
{
|
||||
CallbacksDescriptor d(
|
||||
compilation_type_string, script_compilation_type, attribs);
|
||||
script_map->AppendDescriptor(&d, witness);
|
||||
script_map->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
{
|
||||
CallbacksDescriptor d(line_ends_string, script_line_ends, attribs);
|
||||
script_map->AppendDescriptor(&d, witness);
|
||||
script_map->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
{
|
||||
CallbacksDescriptor d(
|
||||
context_data_string, script_context_data, attribs);
|
||||
script_map->AppendDescriptor(&d, witness);
|
||||
script_map->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
{
|
||||
CallbacksDescriptor d(
|
||||
eval_from_script_string, script_eval_from_script, attribs);
|
||||
script_map->AppendDescriptor(&d, witness);
|
||||
script_map->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
{
|
||||
@ -1817,7 +1792,7 @@ bool Genesis::InstallNatives() {
|
||||
eval_from_script_position_string,
|
||||
script_eval_from_script_position,
|
||||
attribs);
|
||||
script_map->AppendDescriptor(&d, witness);
|
||||
script_map->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
{
|
||||
@ -1825,7 +1800,7 @@ bool Genesis::InstallNatives() {
|
||||
eval_from_function_name_string,
|
||||
script_eval_from_function_name,
|
||||
attribs);
|
||||
script_map->AppendDescriptor(&d, witness);
|
||||
script_map->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
// Allocate the empty script.
|
||||
@ -1945,10 +1920,7 @@ bool Genesis::InstallNatives() {
|
||||
initial_map->set_prototype(*array_prototype);
|
||||
|
||||
// Update map with length accessor from Array and add "index" and "input".
|
||||
Handle<DescriptorArray> reresult_descriptors =
|
||||
factory()->NewDescriptorArray(0, 3);
|
||||
DescriptorArray::WhitenessWitness witness(*reresult_descriptors);
|
||||
initial_map->set_instance_descriptors(*reresult_descriptors);
|
||||
Map::EnsureDescriptorSlack(initial_map, 3);
|
||||
|
||||
{
|
||||
JSFunction* array_function = native_context()->array_function();
|
||||
@ -1962,14 +1934,14 @@ bool Genesis::InstallNatives() {
|
||||
handle(array_descriptors->GetValue(old),
|
||||
isolate()),
|
||||
array_descriptors->GetDetails(old).attributes());
|
||||
initial_map->AppendDescriptor(&desc, witness);
|
||||
initial_map->AppendDescriptor(&desc);
|
||||
}
|
||||
{
|
||||
FieldDescriptor index_field(factory()->index_string(),
|
||||
JSRegExpResult::kIndexIndex,
|
||||
NONE,
|
||||
Representation::Tagged());
|
||||
initial_map->AppendDescriptor(&index_field, witness);
|
||||
initial_map->AppendDescriptor(&index_field);
|
||||
}
|
||||
|
||||
{
|
||||
@ -1977,7 +1949,7 @@ bool Genesis::InstallNatives() {
|
||||
JSRegExpResult::kInputIndex,
|
||||
NONE,
|
||||
Representation::Tagged());
|
||||
initial_map->AppendDescriptor(&input_field, witness);
|
||||
initial_map->AppendDescriptor(&input_field);
|
||||
}
|
||||
|
||||
initial_map->set_inobject_properties(2);
|
||||
|
@ -133,33 +133,6 @@ Handle<WeakHashTable> Factory::NewWeakHashTable(int at_least_space_for) {
|
||||
}
|
||||
|
||||
|
||||
Handle<DescriptorArray> Factory::NewDescriptorArray(int number_of_descriptors,
|
||||
int slack) {
|
||||
ASSERT(0 <= number_of_descriptors);
|
||||
CALL_HEAP_FUNCTION(isolate(),
|
||||
DescriptorArray::Allocate(
|
||||
isolate(), number_of_descriptors, slack),
|
||||
DescriptorArray);
|
||||
}
|
||||
|
||||
|
||||
Handle<TransitionArray> Factory::NewTransitionArray(int number_of_transitions) {
|
||||
ASSERT(0 <= number_of_transitions);
|
||||
CALL_HEAP_FUNCTION(isolate(),
|
||||
TransitionArray::Allocate(
|
||||
isolate(), number_of_transitions),
|
||||
TransitionArray);
|
||||
}
|
||||
|
||||
|
||||
Handle<TransitionArray> Factory::NewSimpleTransitionArray(Handle<Map> target) {
|
||||
CALL_HEAP_FUNCTION(isolate(),
|
||||
TransitionArray::AllocateSimple(
|
||||
isolate(), *target),
|
||||
TransitionArray);
|
||||
}
|
||||
|
||||
|
||||
Handle<DeoptimizationInputData> Factory::NewDeoptimizationInputData(
|
||||
int deopt_entry_count,
|
||||
PretenureFlag pretenure) {
|
||||
|
@ -55,10 +55,6 @@ class Factory V8_FINAL {
|
||||
|
||||
Handle<WeakHashTable> NewWeakHashTable(int at_least_space_for);
|
||||
|
||||
Handle<DescriptorArray> NewDescriptorArray(int number_of_descriptors,
|
||||
int slack = 0);
|
||||
Handle<TransitionArray> NewTransitionArray(int number_of_transitions);
|
||||
Handle<TransitionArray> NewSimpleTransitionArray(Handle<Map> target);
|
||||
Handle<DeoptimizationInputData> NewDeoptimizationInputData(
|
||||
int deopt_entry_count,
|
||||
PretenureFlag pretenure);
|
||||
|
@ -2835,7 +2835,7 @@ void DescriptorArray::SwapSortedKeys(int first, int second) {
|
||||
}
|
||||
|
||||
|
||||
DescriptorArray::WhitenessWitness::WhitenessWitness(FixedArray* array)
|
||||
DescriptorArray::WhitenessWitness::WhitenessWitness(DescriptorArray* array)
|
||||
: marking_(array->GetHeap()->incremental_marking()) {
|
||||
marking_->EnterNoMarkingScope();
|
||||
ASSERT(!marking_->IsMarking() ||
|
||||
@ -4963,21 +4963,18 @@ void Map::set_prototype(Object* value, WriteBarrierMode mode) {
|
||||
|
||||
// If the descriptor is using the empty transition array, install a new empty
|
||||
// transition array that will have place for an element transition.
|
||||
static MaybeObject* EnsureHasTransitionArray(Map* map) {
|
||||
TransitionArray* transitions;
|
||||
MaybeObject* maybe_transitions;
|
||||
static void EnsureHasTransitionArray(Handle<Map> map) {
|
||||
Handle<TransitionArray> transitions;
|
||||
if (!map->HasTransitionArray()) {
|
||||
maybe_transitions = TransitionArray::Allocate(map->GetIsolate(), 0);
|
||||
if (!maybe_transitions->To(&transitions)) return maybe_transitions;
|
||||
transitions = TransitionArray::Allocate(map->GetIsolate(), 0);
|
||||
transitions->set_back_pointer_storage(map->GetBackPointer());
|
||||
} else if (!map->transitions()->IsFullTransitionArray()) {
|
||||
maybe_transitions = map->transitions()->ExtendToFullTransitionArray();
|
||||
if (!maybe_transitions->To(&transitions)) return maybe_transitions;
|
||||
transitions = TransitionArray::ExtendToFullTransitionArray(
|
||||
handle(map->transitions()));
|
||||
} else {
|
||||
return map;
|
||||
return;
|
||||
}
|
||||
map->set_transitions(transitions);
|
||||
return transitions;
|
||||
map->set_transitions(*transitions);
|
||||
}
|
||||
|
||||
|
||||
@ -5018,12 +5015,11 @@ void Map::ClearTransitions(Heap* heap, WriteBarrierMode mode) {
|
||||
}
|
||||
|
||||
|
||||
void Map::AppendDescriptor(Descriptor* desc,
|
||||
const DescriptorArray::WhitenessWitness& witness) {
|
||||
void Map::AppendDescriptor(Descriptor* desc) {
|
||||
DescriptorArray* descriptors = instance_descriptors();
|
||||
int number_of_own_descriptors = NumberOfOwnDescriptors();
|
||||
ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors);
|
||||
descriptors->Append(desc, witness);
|
||||
descriptors->Append(desc);
|
||||
SetNumberOfOwnDescriptors(number_of_own_descriptors + 1);
|
||||
}
|
||||
|
||||
@ -5089,19 +5085,18 @@ FixedArray* Map::GetPrototypeTransitions() {
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Map::SetPrototypeTransitions(FixedArray* proto_transitions) {
|
||||
MaybeObject* allow_prototype = EnsureHasTransitionArray(this);
|
||||
if (allow_prototype->IsFailure()) return allow_prototype;
|
||||
int old_number_of_transitions = NumberOfProtoTransitions();
|
||||
void Map::SetPrototypeTransitions(
|
||||
Handle<Map> map, Handle<FixedArray> proto_transitions) {
|
||||
EnsureHasTransitionArray(map);
|
||||
int old_number_of_transitions = map->NumberOfProtoTransitions();
|
||||
#ifdef DEBUG
|
||||
if (HasPrototypeTransitions()) {
|
||||
ASSERT(GetPrototypeTransitions() != proto_transitions);
|
||||
ZapPrototypeTransitions();
|
||||
if (map->HasPrototypeTransitions()) {
|
||||
ASSERT(map->GetPrototypeTransitions() != *proto_transitions);
|
||||
map->ZapPrototypeTransitions();
|
||||
}
|
||||
#endif
|
||||
transitions()->SetPrototypeTransitions(proto_transitions);
|
||||
SetNumberOfProtoTransitions(old_number_of_transitions);
|
||||
return this;
|
||||
map->transitions()->SetPrototypeTransitions(*proto_transitions);
|
||||
map->SetNumberOfProtoTransitions(old_number_of_transitions);
|
||||
}
|
||||
|
||||
|
||||
|
333
src/objects.cc
333
src/objects.cc
@ -4696,10 +4696,136 @@ void JSObject::TransformToFastProperties(Handle<JSObject> object,
|
||||
int unused_property_fields) {
|
||||
if (object->HasFastProperties()) return;
|
||||
ASSERT(!object->IsGlobalObject());
|
||||
CALL_HEAP_FUNCTION_VOID(
|
||||
object->GetIsolate(),
|
||||
object->property_dictionary()->TransformPropertiesToFastFor(
|
||||
*object, unused_property_fields));
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
Factory* factory = isolate->factory();
|
||||
Handle<NameDictionary> dictionary(object->property_dictionary());
|
||||
|
||||
// Make sure we preserve dictionary representation if there are too many
|
||||
// descriptors.
|
||||
int number_of_elements = dictionary->NumberOfElements();
|
||||
if (number_of_elements > kMaxNumberOfDescriptors) return;
|
||||
|
||||
if (number_of_elements != dictionary->NextEnumerationIndex()) {
|
||||
NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
|
||||
}
|
||||
|
||||
int instance_descriptor_length = 0;
|
||||
int number_of_fields = 0;
|
||||
|
||||
// Compute the length of the instance descriptor.
|
||||
int capacity = dictionary->Capacity();
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* k = dictionary->KeyAt(i);
|
||||
if (dictionary->IsKey(k)) {
|
||||
Object* value = dictionary->ValueAt(i);
|
||||
PropertyType type = dictionary->DetailsAt(i).type();
|
||||
ASSERT(type != FIELD);
|
||||
instance_descriptor_length++;
|
||||
if (type == NORMAL && !value->IsJSFunction()) {
|
||||
number_of_fields += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int inobject_props = object->map()->inobject_properties();
|
||||
|
||||
// Allocate new map.
|
||||
Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
|
||||
new_map->set_dictionary_map(false);
|
||||
|
||||
if (instance_descriptor_length == 0) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
ASSERT_LE(unused_property_fields, inobject_props);
|
||||
// Transform the object.
|
||||
new_map->set_unused_property_fields(inobject_props);
|
||||
object->set_map(*new_map);
|
||||
object->set_properties(isolate->heap()->empty_fixed_array());
|
||||
// Check that it really works.
|
||||
ASSERT(object->HasFastProperties());
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate the instance descriptor.
|
||||
Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
|
||||
isolate, instance_descriptor_length);
|
||||
|
||||
int number_of_allocated_fields =
|
||||
number_of_fields + unused_property_fields - inobject_props;
|
||||
if (number_of_allocated_fields < 0) {
|
||||
// There is enough inobject space for all fields (including unused).
|
||||
number_of_allocated_fields = 0;
|
||||
unused_property_fields = inobject_props - number_of_fields;
|
||||
}
|
||||
|
||||
// Allocate the fixed array for the fields.
|
||||
Handle<FixedArray> fields = factory->NewFixedArray(
|
||||
number_of_allocated_fields);
|
||||
|
||||
// Fill in the instance descriptor and the fields.
|
||||
int current_offset = 0;
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* k = dictionary->KeyAt(i);
|
||||
if (dictionary->IsKey(k)) {
|
||||
Object* value = dictionary->ValueAt(i);
|
||||
Handle<Name> key;
|
||||
if (k->IsSymbol()) {
|
||||
key = handle(Symbol::cast(k));
|
||||
} else {
|
||||
// Ensure the key is a unique name before writing into the
|
||||
// instance descriptor.
|
||||
key = factory->InternalizeString(handle(String::cast(k)));
|
||||
}
|
||||
|
||||
PropertyDetails details = dictionary->DetailsAt(i);
|
||||
int enumeration_index = details.dictionary_index();
|
||||
PropertyType type = details.type();
|
||||
|
||||
if (value->IsJSFunction()) {
|
||||
ConstantDescriptor d(key,
|
||||
handle(value, isolate),
|
||||
details.attributes());
|
||||
descriptors->Set(enumeration_index - 1, &d);
|
||||
} else if (type == NORMAL) {
|
||||
if (current_offset < inobject_props) {
|
||||
object->InObjectPropertyAtPut(current_offset,
|
||||
value,
|
||||
UPDATE_WRITE_BARRIER);
|
||||
} else {
|
||||
int offset = current_offset - inobject_props;
|
||||
fields->set(offset, value);
|
||||
}
|
||||
FieldDescriptor d(key,
|
||||
current_offset++,
|
||||
details.attributes(),
|
||||
// TODO(verwaest): value->OptimalRepresentation();
|
||||
Representation::Tagged());
|
||||
descriptors->Set(enumeration_index - 1, &d);
|
||||
} else if (type == CALLBACKS) {
|
||||
CallbacksDescriptor d(key,
|
||||
handle(value, isolate),
|
||||
details.attributes());
|
||||
descriptors->Set(enumeration_index - 1, &d);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT(current_offset == number_of_fields);
|
||||
|
||||
descriptors->Sort();
|
||||
|
||||
DisallowHeapAllocation no_gc;
|
||||
new_map->InitializeDescriptors(*descriptors);
|
||||
new_map->set_unused_property_fields(unused_property_fields);
|
||||
|
||||
// Transform the object.
|
||||
object->set_map(*new_map);
|
||||
|
||||
object->set_properties(*fields);
|
||||
ASSERT(object->IsJSObject());
|
||||
|
||||
// Check that it really works.
|
||||
ASSERT(object->HasFastProperties());
|
||||
}
|
||||
|
||||
|
||||
@ -6753,23 +6879,17 @@ Handle<Map> Map::CopyNormalized(Handle<Map> map,
|
||||
|
||||
|
||||
Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
|
||||
CALL_HEAP_FUNCTION(map->GetIsolate(), map->CopyDropDescriptors(), Map);
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Map::CopyDropDescriptors() {
|
||||
Map* result;
|
||||
MaybeObject* maybe_result = RawCopy(instance_size());
|
||||
if (!maybe_result->To(&result)) return maybe_result;
|
||||
Handle<Map> result = RawCopy(map, map->instance_size());
|
||||
|
||||
// Please note instance_type and instance_size are set when allocated.
|
||||
result->set_inobject_properties(inobject_properties());
|
||||
result->set_unused_property_fields(unused_property_fields());
|
||||
result->set_inobject_properties(map->inobject_properties());
|
||||
result->set_unused_property_fields(map->unused_property_fields());
|
||||
|
||||
result->set_pre_allocated_property_fields(pre_allocated_property_fields());
|
||||
result->set_pre_allocated_property_fields(
|
||||
map->pre_allocated_property_fields());
|
||||
result->set_is_shared(false);
|
||||
result->ClearCodeCache(GetHeap());
|
||||
NotifyLeafMapLayoutChange();
|
||||
result->ClearCodeCache(map->GetHeap());
|
||||
map->NotifyLeafMapLayoutChange();
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -6792,7 +6912,7 @@ Handle<Map> Map::ShareDescriptor(Handle<Map> map,
|
||||
if (descriptors->NumberOfSlackDescriptors() == 0) {
|
||||
int old_size = descriptors->number_of_descriptors();
|
||||
if (old_size == 0) {
|
||||
descriptors = map->GetIsolate()->factory()->NewDescriptorArray(0, 1);
|
||||
descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
|
||||
} else {
|
||||
Map::EnsureDescriptorSlack(map, old_size < 4 ? 1 : old_size / 2);
|
||||
descriptors = handle(map->instance_descriptors());
|
||||
@ -7060,7 +7180,7 @@ Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
|
||||
int size = enumeration_index;
|
||||
|
||||
Handle<DescriptorArray> descriptors =
|
||||
desc->GetIsolate()->factory()->NewDescriptorArray(size, slack);
|
||||
DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
|
||||
DescriptorArray::WhitenessWitness witness(*descriptors);
|
||||
|
||||
if (attributes != NONE) {
|
||||
@ -7919,21 +8039,20 @@ bool FixedArray::IsEqualTo(FixedArray* other) {
|
||||
#endif
|
||||
|
||||
|
||||
MaybeObject* DescriptorArray::Allocate(Isolate* isolate,
|
||||
int number_of_descriptors,
|
||||
int slack) {
|
||||
Heap* heap = isolate->heap();
|
||||
Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
|
||||
int number_of_descriptors,
|
||||
int slack) {
|
||||
ASSERT(0 <= number_of_descriptors);
|
||||
Factory* factory = isolate->factory();
|
||||
// Do not use DescriptorArray::cast on incomplete object.
|
||||
int size = number_of_descriptors + slack;
|
||||
if (size == 0) return heap->empty_descriptor_array();
|
||||
FixedArray* result;
|
||||
if (size == 0) return factory->empty_descriptor_array();
|
||||
// Allocate the array of keys.
|
||||
MaybeObject* maybe_array = heap->AllocateFixedArray(LengthFor(size));
|
||||
if (!maybe_array->To(&result)) return maybe_array;
|
||||
Handle<FixedArray> result = factory->NewFixedArray(LengthFor(size));
|
||||
|
||||
result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
|
||||
result->set(kEnumCacheIndex, Smi::FromInt(0));
|
||||
return result;
|
||||
return Handle<DescriptorArray>::cast(result);
|
||||
}
|
||||
|
||||
|
||||
@ -7997,11 +8116,13 @@ Handle<DescriptorArray> DescriptorArray::Merge(Handle<Map> left_map,
|
||||
|
||||
// Allocate a new descriptor array large enough to hold the required
|
||||
// descriptors, with minimally the exact same size as this descriptor array.
|
||||
Factory* factory = left_map->GetIsolate()->factory();
|
||||
Isolate* isolate = left_map->GetIsolate();
|
||||
Handle<DescriptorArray> left(left_map->instance_descriptors());
|
||||
Handle<DescriptorArray> right(right_map->instance_descriptors());
|
||||
Handle<DescriptorArray> result = factory->NewDescriptorArray(
|
||||
new_size, Max(new_size, right->number_of_descriptors()) - new_size);
|
||||
Handle<DescriptorArray> result = DescriptorArray::Allocate(
|
||||
isolate,
|
||||
new_size,
|
||||
Max(new_size, right->number_of_descriptors()) - new_size);
|
||||
ASSERT(result->length() > left->length() ||
|
||||
result->NumberOfSlackDescriptors() > 0 ||
|
||||
result->number_of_descriptors() == right->number_of_descriptors());
|
||||
@ -11476,10 +11597,7 @@ Handle<Map> Map::PutPrototypeTransition(Handle<Map> map,
|
||||
Factory* factory = map->GetIsolate()->factory();
|
||||
cache = factory->CopySizeFixedArray(cache, transitions * 2 * step + header);
|
||||
|
||||
CALL_AND_RETRY_OR_DIE(map->GetIsolate(),
|
||||
map->SetPrototypeTransitions(*cache),
|
||||
break,
|
||||
return Handle<Map>());
|
||||
Map::SetPrototypeTransitions(map, cache);
|
||||
}
|
||||
|
||||
// Reload number of transitions as GC might shrink them.
|
||||
@ -15570,151 +15688,6 @@ Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* NameDictionary::TransformPropertiesToFastFor(
|
||||
JSObject* obj, int unused_property_fields) {
|
||||
// Make sure we preserve dictionary representation if there are too many
|
||||
// descriptors.
|
||||
int number_of_elements = NumberOfElements();
|
||||
if (number_of_elements > kMaxNumberOfDescriptors) return obj;
|
||||
|
||||
if (number_of_elements != NextEnumerationIndex()) {
|
||||
MaybeObject* maybe_result = GenerateNewEnumerationIndices();
|
||||
if (maybe_result->IsFailure()) return maybe_result;
|
||||
}
|
||||
|
||||
int instance_descriptor_length = 0;
|
||||
int number_of_fields = 0;
|
||||
|
||||
Heap* heap = GetHeap();
|
||||
|
||||
// Compute the length of the instance descriptor.
|
||||
int capacity = Capacity();
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* k = KeyAt(i);
|
||||
if (IsKey(k)) {
|
||||
Object* value = ValueAt(i);
|
||||
PropertyType type = DetailsAt(i).type();
|
||||
ASSERT(type != FIELD);
|
||||
instance_descriptor_length++;
|
||||
if (type == NORMAL && !value->IsJSFunction()) {
|
||||
number_of_fields += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int inobject_props = obj->map()->inobject_properties();
|
||||
|
||||
// Allocate new map.
|
||||
Map* new_map;
|
||||
MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
|
||||
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
||||
new_map->set_dictionary_map(false);
|
||||
|
||||
if (instance_descriptor_length == 0) {
|
||||
ASSERT_LE(unused_property_fields, inobject_props);
|
||||
// Transform the object.
|
||||
new_map->set_unused_property_fields(inobject_props);
|
||||
obj->set_map(new_map);
|
||||
obj->set_properties(heap->empty_fixed_array());
|
||||
// Check that it really works.
|
||||
ASSERT(obj->HasFastProperties());
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Allocate the instance descriptor.
|
||||
DescriptorArray* descriptors;
|
||||
MaybeObject* maybe_descriptors =
|
||||
DescriptorArray::Allocate(GetIsolate(), instance_descriptor_length);
|
||||
if (!maybe_descriptors->To(&descriptors)) {
|
||||
return maybe_descriptors;
|
||||
}
|
||||
|
||||
DescriptorArray::WhitenessWitness witness(descriptors);
|
||||
|
||||
int number_of_allocated_fields =
|
||||
number_of_fields + unused_property_fields - inobject_props;
|
||||
if (number_of_allocated_fields < 0) {
|
||||
// There is enough inobject space for all fields (including unused).
|
||||
number_of_allocated_fields = 0;
|
||||
unused_property_fields = inobject_props - number_of_fields;
|
||||
}
|
||||
|
||||
// Allocate the fixed array for the fields.
|
||||
FixedArray* fields;
|
||||
MaybeObject* maybe_fields =
|
||||
heap->AllocateFixedArray(number_of_allocated_fields);
|
||||
if (!maybe_fields->To(&fields)) return maybe_fields;
|
||||
|
||||
// Fill in the instance descriptor and the fields.
|
||||
int current_offset = 0;
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* k = KeyAt(i);
|
||||
if (IsKey(k)) {
|
||||
Object* value = ValueAt(i);
|
||||
Name* key;
|
||||
if (k->IsSymbol()) {
|
||||
key = Symbol::cast(k);
|
||||
} else {
|
||||
// Ensure the key is a unique name before writing into the
|
||||
// instance descriptor.
|
||||
MaybeObject* maybe_key = heap->InternalizeString(String::cast(k));
|
||||
if (!maybe_key->To(&key)) return maybe_key;
|
||||
}
|
||||
|
||||
PropertyDetails details = DetailsAt(i);
|
||||
int enumeration_index = details.dictionary_index();
|
||||
PropertyType type = details.type();
|
||||
|
||||
if (value->IsJSFunction()) {
|
||||
ConstantDescriptor d(handle(key),
|
||||
handle(value, GetIsolate()),
|
||||
details.attributes());
|
||||
descriptors->Set(enumeration_index - 1, &d, witness);
|
||||
} else if (type == NORMAL) {
|
||||
if (current_offset < inobject_props) {
|
||||
obj->InObjectPropertyAtPut(current_offset,
|
||||
value,
|
||||
UPDATE_WRITE_BARRIER);
|
||||
} else {
|
||||
int offset = current_offset - inobject_props;
|
||||
fields->set(offset, value);
|
||||
}
|
||||
FieldDescriptor d(handle(key),
|
||||
current_offset++,
|
||||
details.attributes(),
|
||||
// TODO(verwaest): value->OptimalRepresentation();
|
||||
Representation::Tagged());
|
||||
descriptors->Set(enumeration_index - 1, &d, witness);
|
||||
} else if (type == CALLBACKS) {
|
||||
CallbacksDescriptor d(handle(key),
|
||||
handle(value, GetIsolate()),
|
||||
details.attributes());
|
||||
descriptors->Set(enumeration_index - 1, &d, witness);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT(current_offset == number_of_fields);
|
||||
|
||||
descriptors->Sort();
|
||||
|
||||
new_map->InitializeDescriptors(descriptors);
|
||||
new_map->set_unused_property_fields(unused_property_fields);
|
||||
|
||||
// Transform the object.
|
||||
obj->set_map(new_map);
|
||||
|
||||
obj->set_properties(fields);
|
||||
ASSERT(obj->IsJSObject());
|
||||
|
||||
// Check that it really works.
|
||||
ASSERT(obj->HasFastProperties());
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
Handle<ObjectHashTable> ObjectHashTable::EnsureCapacity(
|
||||
Handle<ObjectHashTable> table,
|
||||
int n,
|
||||
|
@ -3349,23 +3349,6 @@ class ConstantPoolArray: public FixedArrayBase {
|
||||
// [2 + number of descriptors * kDescriptorSize]: start of slack
|
||||
class DescriptorArray: public FixedArray {
|
||||
public:
|
||||
// WhitenessWitness is used to prove that a descriptor array is white
|
||||
// (unmarked), so incremental write barriers can be skipped because the
|
||||
// marking invariant cannot be broken and slots pointing into evacuation
|
||||
// candidates will be discovered when the object is scanned. A witness is
|
||||
// always stack-allocated right after creating an array. By allocating a
|
||||
// witness, incremental marking is globally disabled. The witness is then
|
||||
// passed along wherever needed to statically prove that the array is known to
|
||||
// be white.
|
||||
class WhitenessWitness {
|
||||
public:
|
||||
inline explicit WhitenessWitness(FixedArray* array);
|
||||
inline ~WhitenessWitness();
|
||||
|
||||
private:
|
||||
IncrementalMarking* marking_;
|
||||
};
|
||||
|
||||
// Returns true for both shared empty_descriptor_array and for smis, which the
|
||||
// map uses to encode additional bit fields when the descriptor array is not
|
||||
// yet used.
|
||||
@ -3455,15 +3438,12 @@ class DescriptorArray: public FixedArray {
|
||||
|
||||
// Accessor for complete descriptor.
|
||||
inline void Get(int descriptor_number, Descriptor* desc);
|
||||
inline void Set(int descriptor_number,
|
||||
Descriptor* desc,
|
||||
const WhitenessWitness&);
|
||||
inline void Set(int descriptor_number, Descriptor* desc);
|
||||
void Replace(int descriptor_number, Descriptor* descriptor);
|
||||
|
||||
// Append automatically sets the enumeration index. This should only be used
|
||||
// to add descriptors in bulk at the end, followed by sorting the descriptor
|
||||
// array.
|
||||
inline void Append(Descriptor* desc, const WhitenessWitness&);
|
||||
inline void Append(Descriptor* desc);
|
||||
|
||||
static Handle<DescriptorArray> Merge(Handle<Map> left_map,
|
||||
@ -3502,9 +3482,9 @@ class DescriptorArray: public FixedArray {
|
||||
|
||||
// Allocates a DescriptorArray, but returns the singleton
|
||||
// empty descriptor array object if number_of_descriptors is 0.
|
||||
MUST_USE_RESULT static MaybeObject* Allocate(Isolate* isolate,
|
||||
int number_of_descriptors,
|
||||
int slack = 0);
|
||||
static Handle<DescriptorArray> Allocate(Isolate* isolate,
|
||||
int number_of_descriptors,
|
||||
int slack = 0);
|
||||
|
||||
// Casting.
|
||||
static inline DescriptorArray* cast(Object* obj);
|
||||
@ -3558,6 +3538,23 @@ class DescriptorArray: public FixedArray {
|
||||
}
|
||||
|
||||
private:
|
||||
// WhitenessWitness is used to prove that a descriptor array is white
|
||||
// (unmarked), so incremental write barriers can be skipped because the
|
||||
// marking invariant cannot be broken and slots pointing into evacuation
|
||||
// candidates will be discovered when the object is scanned. A witness is
|
||||
// always stack-allocated right after creating an array. By allocating a
|
||||
// witness, incremental marking is globally disabled. The witness is then
|
||||
// passed along wherever needed to statically prove that the array is known to
|
||||
// be white.
|
||||
class WhitenessWitness {
|
||||
public:
|
||||
inline explicit WhitenessWitness(DescriptorArray* array);
|
||||
inline ~WhitenessWitness();
|
||||
|
||||
private:
|
||||
IncrementalMarking* marking_;
|
||||
};
|
||||
|
||||
// An entry in a DescriptorArray, represented as an (array, index) pair.
|
||||
class Entry {
|
||||
public:
|
||||
@ -3597,7 +3594,11 @@ class DescriptorArray: public FixedArray {
|
||||
DescriptorArray* src,
|
||||
const WhitenessWitness&);
|
||||
|
||||
inline void Set(int descriptor_number, Descriptor* desc);
|
||||
inline void Set(int descriptor_number,
|
||||
Descriptor* desc,
|
||||
const WhitenessWitness&);
|
||||
|
||||
inline void Append(Descriptor* desc, const WhitenessWitness&);
|
||||
|
||||
// Swap first and second descriptor.
|
||||
inline void SwapSortedKeys(int first, int second);
|
||||
@ -4099,11 +4100,6 @@ class NameDictionary: public Dictionary<NameDictionaryShape, Name*> {
|
||||
static void DoGenerateNewEnumerationIndices(
|
||||
Handle<NameDictionary> dictionary);
|
||||
|
||||
// For transforming properties of a JSObject.
|
||||
MUST_USE_RESULT MaybeObject* TransformPropertiesToFastFor(
|
||||
JSObject* obj,
|
||||
int unused_property_fields);
|
||||
|
||||
// Find entry for key, otherwise return kNotFound. Optimized version of
|
||||
// HashTable::FindEntry.
|
||||
int FindEntry(Name* key);
|
||||
@ -6336,8 +6332,8 @@ class Map: public HeapObject {
|
||||
// 2 + 2 * i: prototype
|
||||
// 3 + 2 * i: target map
|
||||
inline FixedArray* GetPrototypeTransitions();
|
||||
MUST_USE_RESULT inline MaybeObject* SetPrototypeTransitions(
|
||||
FixedArray* prototype_transitions);
|
||||
static inline void SetPrototypeTransitions(
|
||||
Handle<Map> map, Handle<FixedArray> prototype_transitions);
|
||||
inline bool HasPrototypeTransitions();
|
||||
|
||||
static const int kProtoTransitionHeaderSize = 1;
|
||||
@ -6432,7 +6428,6 @@ class Map: public HeapObject {
|
||||
static Handle<Map> RawCopy(Handle<Map> map, int instance_size);
|
||||
MUST_USE_RESULT MaybeObject* RawCopy(int instance_size);
|
||||
static Handle<Map> CopyDropDescriptors(Handle<Map> map);
|
||||
MUST_USE_RESULT MaybeObject* CopyDropDescriptors();
|
||||
static Handle<Map> CopyReplaceDescriptors(
|
||||
Handle<Map> map,
|
||||
Handle<DescriptorArray> descriptors,
|
||||
@ -6476,8 +6471,7 @@ class Map: public HeapObject {
|
||||
PropertyNormalizationMode mode,
|
||||
NormalizedMapSharingMode sharing);
|
||||
|
||||
inline void AppendDescriptor(Descriptor* desc,
|
||||
const DescriptorArray::WhitenessWitness&);
|
||||
inline void AppendDescriptor(Descriptor* desc);
|
||||
|
||||
// Returns a copy of the map, with all transitions dropped from the
|
||||
// instance descriptors.
|
||||
|
@ -35,34 +35,21 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
static MaybeObject* AllocateRaw(Isolate* isolate, int length) {
|
||||
// Use FixedArray to not use TransitionArray::cast on incomplete object.
|
||||
FixedArray* array;
|
||||
MaybeObject* maybe_array = isolate->heap()->AllocateFixedArray(length);
|
||||
if (!maybe_array->To(&array)) return maybe_array;
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* TransitionArray::Allocate(Isolate* isolate,
|
||||
int number_of_transitions) {
|
||||
FixedArray* array;
|
||||
MaybeObject* maybe_array =
|
||||
AllocateRaw(isolate, ToKeyIndex(number_of_transitions));
|
||||
if (!maybe_array->To(&array)) return maybe_array;
|
||||
Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate,
|
||||
int number_of_transitions) {
|
||||
Handle<FixedArray> array =
|
||||
isolate->factory()->NewFixedArray(ToKeyIndex(number_of_transitions));
|
||||
array->set(kPrototypeTransitionsIndex, Smi::FromInt(0));
|
||||
return array;
|
||||
return Handle<TransitionArray>::cast(array);
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* TransitionArray::AllocateSimple(Isolate* isolate,
|
||||
Map* target) {
|
||||
FixedArray* array;
|
||||
MaybeObject* maybe_array =
|
||||
AllocateRaw(isolate, kSimpleTransitionSize);
|
||||
if (!maybe_array->To(&array)) return maybe_array;
|
||||
array->set(kSimpleTransitionTarget, target);
|
||||
return array;
|
||||
Handle<TransitionArray> TransitionArray::AllocateSimple(Isolate* isolate,
|
||||
Handle<Map> target) {
|
||||
Handle<FixedArray> array =
|
||||
isolate->factory()->NewFixedArray(kSimpleTransitionSize);
|
||||
array->set(kSimpleTransitionTarget, *target);
|
||||
return Handle<TransitionArray>::cast(array);
|
||||
}
|
||||
|
||||
|
||||
@ -85,12 +72,12 @@ Handle<TransitionArray> TransitionArray::NewWith(Handle<Map> map,
|
||||
Handle<Map> target,
|
||||
SimpleTransitionFlag flag) {
|
||||
Handle<TransitionArray> result;
|
||||
Factory* factory = name->GetIsolate()->factory();
|
||||
Isolate* isolate = name->GetIsolate();
|
||||
|
||||
if (flag == SIMPLE_TRANSITION) {
|
||||
result = factory->NewSimpleTransitionArray(target);
|
||||
result = AllocateSimple(isolate, target);
|
||||
} else {
|
||||
result = factory->NewTransitionArray(1);
|
||||
result = Allocate(isolate, 1);
|
||||
result->NoIncrementalWriteBarrierSet(0, *name, *target);
|
||||
}
|
||||
result->set_back_pointer_storage(map->GetBackPointer());
|
||||
@ -98,18 +85,18 @@ Handle<TransitionArray> TransitionArray::NewWith(Handle<Map> map,
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* TransitionArray::ExtendToFullTransitionArray() {
|
||||
ASSERT(!IsFullTransitionArray());
|
||||
int nof = number_of_transitions();
|
||||
TransitionArray* result;
|
||||
MaybeObject* maybe_result = Allocate(GetIsolate(), nof);
|
||||
if (!maybe_result->To(&result)) return maybe_result;
|
||||
Handle<TransitionArray> TransitionArray::ExtendToFullTransitionArray(
|
||||
Handle<TransitionArray> array) {
|
||||
ASSERT(!array->IsFullTransitionArray());
|
||||
int nof = array->number_of_transitions();
|
||||
Handle<TransitionArray> result = Allocate(array->GetIsolate(), nof);
|
||||
|
||||
if (nof == 1) {
|
||||
result->NoIncrementalWriteBarrierCopyFrom(this, kSimpleTransitionIndex, 0);
|
||||
result->NoIncrementalWriteBarrierCopyFrom(
|
||||
*array, kSimpleTransitionIndex, 0);
|
||||
}
|
||||
|
||||
result->set_back_pointer_storage(back_pointer_storage());
|
||||
result->set_back_pointer_storage(array->back_pointer_storage());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -128,8 +115,7 @@ Handle<TransitionArray> TransitionArray::CopyInsert(Handle<Map> map,
|
||||
int insertion_index = map->transitions()->Search(*name);
|
||||
if (insertion_index == kNotFound) ++new_size;
|
||||
|
||||
Handle<TransitionArray> result =
|
||||
map->GetIsolate()->factory()->NewTransitionArray(new_size);
|
||||
Handle<TransitionArray> result = Allocate(map->GetIsolate(), new_size);
|
||||
|
||||
// The map's transition array may have disappeared or grown smaller during
|
||||
// the allocation above as it was weakly traversed. Trim the result copy if
|
||||
|
@ -95,13 +95,8 @@ class TransitionArray: public FixedArray {
|
||||
|
||||
inline int number_of_entries() { return number_of_transitions(); }
|
||||
|
||||
// Allocate a new transition array with a single entry.
|
||||
static Handle<TransitionArray> NewWith(Handle<Map> map,
|
||||
Handle<Name> name,
|
||||
Handle<Map> target,
|
||||
SimpleTransitionFlag flag);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* ExtendToFullTransitionArray();
|
||||
static Handle<TransitionArray> ExtendToFullTransitionArray(
|
||||
Handle<TransitionArray> array);
|
||||
|
||||
// Create a transition array, copying from the owning map if it already has
|
||||
// one, otherwise creating a new one according to flag.
|
||||
@ -112,21 +107,13 @@ class TransitionArray: public FixedArray {
|
||||
Handle<Map> target,
|
||||
SimpleTransitionFlag flag);
|
||||
|
||||
// Copy a single transition from the origin array.
|
||||
inline void NoIncrementalWriteBarrierCopyFrom(TransitionArray* origin,
|
||||
int origin_transition,
|
||||
int target_transition);
|
||||
|
||||
// Search a transition for a given property name.
|
||||
inline int Search(Name* name);
|
||||
|
||||
// Allocates a TransitionArray.
|
||||
MUST_USE_RESULT static MaybeObject* Allocate(
|
||||
static Handle<TransitionArray> Allocate(
|
||||
Isolate* isolate, int number_of_transitions);
|
||||
|
||||
MUST_USE_RESULT static MaybeObject* AllocateSimple(
|
||||
Isolate* isolate, Map* target);
|
||||
|
||||
bool IsSimpleTransition() {
|
||||
return length() == kSimpleTransitionSize &&
|
||||
get(kSimpleTransitionTarget)->IsHeapObject() &&
|
||||
@ -204,10 +191,24 @@ class TransitionArray: public FixedArray {
|
||||
kTransitionTarget;
|
||||
}
|
||||
|
||||
static Handle<TransitionArray> AllocateSimple(
|
||||
Isolate* isolate, Handle<Map> target);
|
||||
|
||||
// Allocate a new transition array with a single entry.
|
||||
static Handle<TransitionArray> NewWith(Handle<Map> map,
|
||||
Handle<Name> name,
|
||||
Handle<Map> target,
|
||||
SimpleTransitionFlag flag);
|
||||
|
||||
inline void NoIncrementalWriteBarrierSet(int transition_number,
|
||||
Name* key,
|
||||
Map* target);
|
||||
|
||||
// Copy a single transition from the origin array.
|
||||
inline void NoIncrementalWriteBarrierCopyFrom(TransitionArray* origin,
|
||||
int origin_transition,
|
||||
int target_transition);
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(TransitionArray);
|
||||
};
|
||||
|
||||
|
@ -137,15 +137,12 @@ TEST(StressJS) {
|
||||
factory->NewStringFromAscii(Vector<const char>("get", 3));
|
||||
ASSERT(instance_descriptors->IsEmpty());
|
||||
|
||||
Handle<DescriptorArray> new_descriptors = factory->NewDescriptorArray(0, 1);
|
||||
|
||||
v8::internal::DescriptorArray::WhitenessWitness witness(*new_descriptors);
|
||||
map->set_instance_descriptors(*new_descriptors);
|
||||
Map::EnsureDescriptorSlack(map, 1);
|
||||
|
||||
CallbacksDescriptor d(name,
|
||||
foreign,
|
||||
static_cast<PropertyAttributes>(0));
|
||||
map->AppendDescriptor(&d, witness);
|
||||
map->AppendDescriptor(&d);
|
||||
|
||||
// Add the Foo constructor the global object.
|
||||
env->Global()->Set(v8::String::NewFromUtf8(CcTest::isolate(), "Foo"),
|
||||
|
Loading…
Reference in New Issue
Block a user