| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 74c708ef1855db99d7c2bbd88e7279a584e34bab..1770c9bd313a660c1f23f14ab1aa1b9aae713424 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -30,17 +30,24 @@
|
| #include "api.h"
|
| #include "arguments.h"
|
| #include "bootstrapper.h"
|
| +#include "codegen.h"
|
| #include "debug.h"
|
| +#include "deoptimizer.h"
|
| #include "execution.h"
|
| +#include "full-codegen.h"
|
| +#include "hydrogen.h"
|
| #include "objects-inl.h"
|
| #include "objects-visiting.h"
|
| #include "macro-assembler.h"
|
| +#include "safepoint-table.h"
|
| #include "scanner-base.h"
|
| #include "scopeinfo.h"
|
| #include "string-stream.h"
|
| #include "utils.h"
|
| +#include "vm-state-inl.h"
|
|
|
| #ifdef ENABLE_DISASSEMBLER
|
| +#include "disasm.h"
|
| #include "disassembler.h"
|
| #endif
|
|
|
| @@ -1766,6 +1773,24 @@ void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
|
| }
|
|
|
|
|
| +void Map::LookupInDescriptors(JSObject* holder,
|
| + String* name,
|
| + LookupResult* result) {
|
| + DescriptorArray* descriptors = instance_descriptors();
|
| + DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache();
|
| + int number = cache->Lookup(descriptors, name);
|
| + if (number == DescriptorLookupCache::kAbsent) {
|
| + number = descriptors->Search(name);
|
| + cache->Update(descriptors, name, number);
|
| + }
|
| + if (number != DescriptorArray::kNotFound) {
|
| + result->DescriptorResult(holder, descriptors->GetDetails(number), number);
|
| + } else {
|
| + result->NotFound();
|
| + }
|
| +}
|
| +
|
| +
|
| void JSObject::LocalLookupRealNamedProperty(String* name,
|
| LookupResult* result) {
|
| if (IsJSGlobalProxy()) {
|
| @@ -3117,6 +3142,10 @@ MaybeObject* JSObject::SetPropertyCallback(String* name,
|
| if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
|
| }
|
| set_map(Map::cast(new_map));
|
| + // When running crankshaft, changing the map is not enough. We
|
| + // need to deoptimize all functions that rely on this global
|
| + // object.
|
| + Deoptimizer::DeoptimizeGlobalObject(this);
|
| }
|
|
|
| // Update the dictionary with the new CALLBACKS property.
|
| @@ -4203,6 +4232,22 @@ int DescriptorArray::LinearSearch(String* name, int len) {
|
| }
|
|
|
|
|
| +MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
|
| + PretenureFlag pretenure) {
|
| + ASSERT(deopt_entry_count > 0);
|
| + return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
|
| + pretenure);
|
| +}
|
| +
|
| +
|
| +MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
|
| + PretenureFlag pretenure) {
|
| + if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
|
| + return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
|
| + pretenure);
|
| +}
|
| +
|
| +
|
| #ifdef DEBUG
|
| bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
|
| if (IsEmpty()) return other->IsEmpty();
|
| @@ -4217,7 +4262,7 @@ bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
|
|
|
|
|
| bool String::LooksValid() {
|
| - if (!GetHeap()->Contains(this)) return false;
|
| + if (!Isolate::Current()->heap()->Contains(this)) return false;
|
| return true;
|
| }
|
|
|
| @@ -4298,10 +4343,10 @@ SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
|
| int length,
|
| int* length_return) {
|
| ASSERT(NativeAllocationChecker::allocation_allowed());
|
| - Heap* heap = GetHeap();
|
| if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
|
| return SmartPointer<char>(NULL);
|
| }
|
| + Heap* heap = GetHeap();
|
|
|
| // Negative length means the to the end of the string.
|
| if (length < 0) length = kMaxInt - offset;
|
| @@ -4377,12 +4422,11 @@ const uc16* String::GetTwoByteData(unsigned start) {
|
|
|
|
|
| SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
|
| - Heap* heap = GetHeap();
|
| ASSERT(NativeAllocationChecker::allocation_allowed());
|
| -
|
| if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
|
| return SmartPointer<uc16>();
|
| }
|
| + Heap* heap = GetHeap();
|
|
|
| Access<StringInputBuffer> buffer(
|
| heap->isolate()->objects_string_input_buffer());
|
| @@ -5423,6 +5467,39 @@ void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
|
| }
|
|
|
|
|
| +void JSFunction::MarkForLazyRecompilation() {
|
| + ASSERT(is_compiled() && !IsOptimized());
|
| + ASSERT(shared()->allows_lazy_compilation());
|
| + Builtins* builtins = GetIsolate()->builtins();
|
| + ReplaceCode(builtins->builtin(Builtins::LazyRecompile));
|
| +}
|
| +
|
| +
|
| +uint32_t JSFunction::SourceHash() {
|
| + uint32_t hash = 0;
|
| + Object* script = shared()->script();
|
| + if (!script->IsUndefined()) {
|
| + Object* source = Script::cast(script)->source();
|
| + if (source->IsUndefined()) hash = String::cast(source)->Hash();
|
| + }
|
| + hash ^= ComputeIntegerHash(shared()->start_position_and_type());
|
| + hash += ComputeIntegerHash(shared()->end_position());
|
| + return hash;
|
| +}
|
| +
|
| +
|
| +bool JSFunction::IsInlineable() {
|
| + if (IsBuiltin()) return false;
|
| + // Check that the function has a script associated with it.
|
| + if (!shared()->script()->IsScript()) return false;
|
| + Code* code = shared()->code();
|
| + if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
|
| + // If we never ran this (unlikely) then lets try to optimize it.
|
| + if (code->kind() != Code::FUNCTION) return true;
|
| + return code->optimizable();
|
| +}
|
| +
|
| +
|
| Object* JSFunction::SetInstancePrototype(Object* value) {
|
| ASSERT(value->IsJSObject());
|
| Heap* heap = GetHeap();
|
| @@ -5485,6 +5562,12 @@ Object* JSFunction::SetInstanceClassName(String* name) {
|
| }
|
|
|
|
|
| +void JSFunction::PrintName() {
|
| + SmartPointer<char> name = shared()->DebugName()->ToCString();
|
| + PrintF("%s", *name);
|
| +}
|
| +
|
| +
|
| Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
|
| return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
|
| }
|
| @@ -5519,16 +5602,20 @@ bool SharedFunctionInfo::HasSourceCode() {
|
|
|
|
|
| Object* SharedFunctionInfo::GetSourceCode() {
|
| - Heap* heap = GetHeap();
|
| - HandleScope scope;
|
| - if (script()->IsUndefined()) return heap->undefined_value();
|
| + Isolate* isolate = GetIsolate();
|
| + if (!HasSourceCode()) return isolate->heap()->undefined_value();
|
| + HandleScope scope(isolate);
|
| Object* source = Script::cast(script())->source();
|
| - if (source->IsUndefined()) return heap->undefined_value();
|
| - return *SubString(Handle<String>(String::cast(source)),
|
| + return *SubString(Handle<String>(String::cast(source), isolate),
|
| start_position(), end_position());
|
| }
|
|
|
|
|
| +int SharedFunctionInfo::SourceSize() {
|
| + return end_position() - start_position();
|
| +}
|
| +
|
| +
|
| int SharedFunctionInfo::CalculateInstanceSize() {
|
| int instance_size =
|
| JSObject::kHeaderSize +
|
| @@ -5649,8 +5736,7 @@ Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
|
| void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
|
| int max_length) {
|
| // For some native functions there is no source.
|
| - if (script()->IsUndefined() ||
|
| - Script::cast(script())->source()->IsUndefined()) {
|
| + if (!HasSourceCode()) {
|
| accumulator->Add("<No Source>");
|
| return;
|
| }
|
| @@ -5675,14 +5761,60 @@ void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
|
| }
|
|
|
| int len = end_position() - start_position();
|
| - if (len > max_length) {
|
| + if (len <= max_length || max_length < 0) {
|
| + accumulator->Put(script_source, start_position(), end_position());
|
| + } else {
|
| accumulator->Put(script_source,
|
| start_position(),
|
| start_position() + max_length);
|
| accumulator->Add("...\n");
|
| + }
|
| +}
|
| +
|
| +
|
| +static bool IsCodeEquivalent(Code* code, Code* recompiled) {
|
| + if (code->instruction_size() != recompiled->instruction_size()) return false;
|
| + ByteArray* code_relocation = code->relocation_info();
|
| + ByteArray* recompiled_relocation = recompiled->relocation_info();
|
| + int length = code_relocation->length();
|
| + if (length != recompiled_relocation->length()) return false;
|
| + int compare = memcmp(code_relocation->GetDataStartAddress(),
|
| + recompiled_relocation->GetDataStartAddress(),
|
| + length);
|
| + return compare == 0;
|
| +}
|
| +
|
| +
|
| +void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
|
| + ASSERT(!has_deoptimization_support());
|
| + AssertNoAllocation no_allocation;
|
| + Code* code = this->code();
|
| + if (IsCodeEquivalent(code, recompiled)) {
|
| + // Copy the deoptimization data from the recompiled code.
|
| + code->set_deoptimization_data(recompiled->deoptimization_data());
|
| + code->set_has_deoptimization_support(true);
|
| } else {
|
| - accumulator->Put(script_source, start_position(), end_position());
|
| + // TODO(3025757): In case the recompiled isn't equivalent to the
|
| + // old code, we have to replace it. We should try to avoid this
|
| + // altogether because it flushes valuable type feedback by
|
| + // effectively resetting all IC state.
|
| + set_code(recompiled);
|
| }
|
| + ASSERT(has_deoptimization_support());
|
| +}
|
| +
|
| +
|
| +bool SharedFunctionInfo::VerifyBailoutId(int id) {
|
| + // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
|
| + // we are always bailing out on ARM.
|
| +
|
| + ASSERT(id != AstNode::kNoNumber);
|
| + Code* unoptimized = code();
|
| + DeoptimizationOutputData* data =
|
| + DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
|
| + unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
|
| + USE(ignore);
|
| + return true; // Return true if there was no ASSERT.
|
| }
|
|
|
|
|
| @@ -5811,6 +5943,17 @@ void ObjectVisitor::VisitCodeEntry(Address entry_address) {
|
| }
|
|
|
|
|
| +void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
|
| + ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
|
| + Object* cell = rinfo->target_cell();
|
| + Object* old_cell = cell;
|
| + VisitPointer(&cell);
|
| + if (cell != old_cell) {
|
| + rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
|
| + }
|
| +}
|
| +
|
| +
|
| void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
|
| ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
|
| rinfo->IsPatchedReturnSequence()) ||
|
| @@ -5823,6 +5966,11 @@ void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
|
| }
|
|
|
|
|
| +void Code::InvalidateRelocation() {
|
| + set_relocation_info(GetHeap()->empty_byte_array());
|
| +}
|
| +
|
| +
|
| void Code::Relocate(intptr_t delta) {
|
| for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
|
| it.rinfo()->apply(delta);
|
| @@ -5844,6 +5992,7 @@ void Code::CopyFrom(const CodeDesc& desc) {
|
| intptr_t delta = instruction_start() - desc.buffer;
|
| int mode_mask = RelocInfo::kCodeTargetMask |
|
| RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
|
| + RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
|
| RelocInfo::kApplyMask;
|
| Assembler* origin = desc.origin; // Needed to find target_object on X64.
|
| for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
|
| @@ -5851,6 +6000,9 @@ void Code::CopyFrom(const CodeDesc& desc) {
|
| if (mode == RelocInfo::EMBEDDED_OBJECT) {
|
| Handle<Object> p = it.rinfo()->target_object_handle(origin);
|
| it.rinfo()->set_target_object(*p);
|
| + } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
|
| + Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
|
| + it.rinfo()->set_target_cell(*cell);
|
| } else if (RelocInfo::IsCodeTarget(mode)) {
|
| // rewrite code handles in inline cache targets to direct
|
| // pointers to the first instruction in the code object
|
| @@ -5921,11 +6073,194 @@ int Code::SourceStatementPosition(Address pc) {
|
| }
|
|
|
|
|
| +uint8_t* Code::GetSafepointEntry(Address pc) {
|
| + SafepointTable table(this);
|
| + unsigned pc_offset = pc - instruction_start();
|
| + for (unsigned i = 0; i < table.length(); i++) {
|
| + // TODO(kasperl): Replace the linear search with binary search.
|
| + if (table.GetPcOffset(i) == pc_offset) return table.GetEntry(i);
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +void Code::SetNoStackCheckTable() {
|
| + // Indicate the absence of a stack-check table by a table start after the
|
| + // end of the instructions. Table start must be aligned, so round up.
|
| + set_stack_check_table_start(RoundUp(instruction_size(), kIntSize));
|
| +}
|
| +
|
| +
|
| +Map* Code::FindFirstMap() {
|
| + ASSERT(is_inline_cache_stub());
|
| + AssertNoAllocation no_allocation;
|
| + int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
|
| + for (RelocIterator it(this, mask); !it.done(); it.next()) {
|
| + RelocInfo* info = it.rinfo();
|
| + Object* object = info->target_object();
|
| + if (object->IsMap()) return Map::cast(object);
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| #ifdef ENABLE_DISASSEMBLER
|
| +
|
| +#ifdef DEBUG
|
| +
|
| +void DeoptimizationInputData::DeoptimizationInputDataPrint() {
|
| + disasm::NameConverter converter;
|
| + int deopt_count = DeoptCount();
|
| + PrintF("Deoptimization Input Data (deopt points = %d)\n", deopt_count);
|
| + if (0 == deopt_count) return;
|
| +
|
| + PrintF("%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands");
|
| + for (int i = 0; i < deopt_count; i++) {
|
| + int command_count = 0;
|
| + PrintF("%6d %6d %6d",
|
| + i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
|
| + int translation_index = TranslationIndex(i)->value();
|
| + TranslationIterator iterator(TranslationByteArray(), translation_index);
|
| + Translation::Opcode opcode =
|
| + static_cast<Translation::Opcode>(iterator.Next());
|
| + ASSERT(Translation::BEGIN == opcode);
|
| + int frame_count = iterator.Next();
|
| + if (FLAG_print_code_verbose) {
|
| + PrintF(" %s {count=%d}\n", Translation::StringFor(opcode), frame_count);
|
| + }
|
| +
|
| + for (int i = 0; i < frame_count; ++i) {
|
| + opcode = static_cast<Translation::Opcode>(iterator.Next());
|
| + ASSERT(Translation::FRAME == opcode);
|
| + int ast_id = iterator.Next();
|
| + int function_id = iterator.Next();
|
| + JSFunction* function =
|
| + JSFunction::cast(LiteralArray()->get(function_id));
|
| + unsigned height = iterator.Next();
|
| + if (FLAG_print_code_verbose) {
|
| + PrintF("%24s %s {ast_id=%d, function=",
|
| + "", Translation::StringFor(opcode), ast_id);
|
| + function->PrintName();
|
| + PrintF(", height=%u}\n", height);
|
| + }
|
| +
|
| + // Size of translation is height plus all incoming arguments including
|
| + // receiver.
|
| + int size = height + function->shared()->formal_parameter_count() + 1;
|
| + command_count += size;
|
| + for (int j = 0; j < size; ++j) {
|
| + opcode = static_cast<Translation::Opcode>(iterator.Next());
|
| + if (FLAG_print_code_verbose) {
|
| + PrintF("%24s %s ", "", Translation::StringFor(opcode));
|
| + }
|
| +
|
| + if (opcode == Translation::DUPLICATE) {
|
| + opcode = static_cast<Translation::Opcode>(iterator.Next());
|
| + if (FLAG_print_code_verbose) {
|
| + PrintF("%s ", Translation::StringFor(opcode));
|
| + }
|
| + --j; // Two commands share the same frame index.
|
| + }
|
| +
|
| + switch (opcode) {
|
| + case Translation::BEGIN:
|
| + case Translation::FRAME:
|
| + case Translation::DUPLICATE:
|
| + UNREACHABLE();
|
| + break;
|
| +
|
| + case Translation::REGISTER: {
|
| + int reg_code = iterator.Next();
|
| + if (FLAG_print_code_verbose) {
|
| + PrintF("{input=%s}", converter.NameOfCPURegister(reg_code));
|
| + }
|
| + break;
|
| + }
|
| +
|
| + case Translation::INT32_REGISTER: {
|
| + int reg_code = iterator.Next();
|
| + if (FLAG_print_code_verbose) {
|
| + PrintF("{input=%s}", converter.NameOfCPURegister(reg_code));
|
| + }
|
| + break;
|
| + }
|
| +
|
| + case Translation::DOUBLE_REGISTER: {
|
| + int reg_code = iterator.Next();
|
| + if (FLAG_print_code_verbose) {
|
| + PrintF("{input=%s}",
|
| + DoubleRegister::AllocationIndexToString(reg_code));
|
| + }
|
| + break;
|
| + }
|
| +
|
| + case Translation::STACK_SLOT: {
|
| + int input_slot_index = iterator.Next();
|
| + if (FLAG_print_code_verbose) {
|
| + PrintF("{input=%d}", input_slot_index);
|
| + }
|
| + break;
|
| + }
|
| +
|
| + case Translation::INT32_STACK_SLOT: {
|
| + int input_slot_index = iterator.Next();
|
| + if (FLAG_print_code_verbose) {
|
| + PrintF("{input=%d}", input_slot_index);
|
| + }
|
| + break;
|
| + }
|
| +
|
| + case Translation::DOUBLE_STACK_SLOT: {
|
| + int input_slot_index = iterator.Next();
|
| + if (FLAG_print_code_verbose) {
|
| + PrintF("{input=%d}", input_slot_index);
|
| + }
|
| + break;
|
| + }
|
| +
|
| + case Translation::LITERAL: {
|
| + unsigned literal_index = iterator.Next();
|
| + if (FLAG_print_code_verbose) {
|
| + PrintF("{literal_id=%u}", literal_index);
|
| + }
|
| + break;
|
| + }
|
| +
|
| + case Translation::ARGUMENTS_OBJECT:
|
| + break;
|
| + }
|
| + if (FLAG_print_code_verbose) PrintF("\n");
|
| + }
|
| + }
|
| + if (!FLAG_print_code_verbose) PrintF(" %12d\n", command_count);
|
| + }
|
| +}
|
| +
|
| +
|
| +void DeoptimizationOutputData::DeoptimizationOutputDataPrint() {
|
| + PrintF("Deoptimization Output Data (deopt points = %d)\n",
|
| + this->DeoptPoints());
|
| + if (this->DeoptPoints() == 0) return;
|
| +
|
| + PrintF("%6s %8s %s\n", "ast id", "pc", "state");
|
| + for (int i = 0; i < this->DeoptPoints(); i++) {
|
| + int pc_and_state = this->PcAndState(i)->value();
|
| + PrintF("%6d %8d %s\n",
|
| + this->AstId(i)->value(),
|
| + FullCodeGenerator::PcField::decode(pc_and_state),
|
| + FullCodeGenerator::State2String(
|
| + FullCodeGenerator::StateField::decode(pc_and_state)));
|
| + }
|
| +}
|
| +
|
| +#endif
|
| +
|
| +
|
| // Identify kind of code.
|
| const char* Code::Kind2String(Kind kind) {
|
| switch (kind) {
|
| case FUNCTION: return "FUNCTION";
|
| + case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
|
| case STUB: return "STUB";
|
| case BUILTIN: return "BUILTIN";
|
| case LOAD_IC: return "LOAD_IC";
|
| @@ -5935,6 +6270,8 @@ const char* Code::Kind2String(Kind kind) {
|
| case CALL_IC: return "CALL_IC";
|
| case KEYED_CALL_IC: return "KEYED_CALL_IC";
|
| case BINARY_OP_IC: return "BINARY_OP_IC";
|
| + case TYPE_RECORDING_BINARY_OP_IC: return "TYPE_RECORDING_BINARY_OP_IC";
|
| + case COMPARE_IC: return "COMPARE_IC";
|
| }
|
| UNREACHABLE();
|
| return NULL;
|
| @@ -5971,6 +6308,7 @@ const char* Code::PropertyType2String(PropertyType type) {
|
| return NULL;
|
| }
|
|
|
| +
|
| void Code::Disassemble(const char* name) {
|
| PrintF("kind = %s\n", Kind2String(kind()));
|
| if (is_inline_cache_stub()) {
|
| @@ -5983,14 +6321,64 @@ void Code::Disassemble(const char* name) {
|
| if ((name != NULL) && (name[0] != '\0')) {
|
| PrintF("name = %s\n", name);
|
| }
|
| + if (kind() == OPTIMIZED_FUNCTION) {
|
| + PrintF("stack_slots = %d\n", stack_slots());
|
| + }
|
|
|
| PrintF("Instructions (size = %d)\n", instruction_size());
|
| Disassembler::Decode(NULL, this);
|
| PrintF("\n");
|
|
|
| +#ifdef DEBUG
|
| + if (kind() == FUNCTION) {
|
| + DeoptimizationOutputData* data =
|
| + DeoptimizationOutputData::cast(this->deoptimization_data());
|
| + data->DeoptimizationOutputDataPrint();
|
| + } else if (kind() == OPTIMIZED_FUNCTION) {
|
| + DeoptimizationInputData* data =
|
| + DeoptimizationInputData::cast(this->deoptimization_data());
|
| + data->DeoptimizationInputDataPrint();
|
| + }
|
| + PrintF("\n");
|
| +#endif
|
| +
|
| + if (kind() == OPTIMIZED_FUNCTION) {
|
| + SafepointTable table(this);
|
| + PrintF("Safepoints (size = %u)\n", table.size());
|
| + for (unsigned i = 0; i < table.length(); i++) {
|
| + unsigned pc_offset = table.GetPcOffset(i);
|
| + PrintF("%p %4d ", (instruction_start() + pc_offset), pc_offset);
|
| + table.PrintEntry(i);
|
| + PrintF(" (sp -> fp)");
|
| + int deoptimization_index = table.GetDeoptimizationIndex(i);
|
| + if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
|
| + PrintF(" %6d", deoptimization_index);
|
| + } else {
|
| + PrintF(" <none>");
|
| + }
|
| + PrintF("\n");
|
| + }
|
| + PrintF("\n");
|
| + } else if (kind() == FUNCTION) {
|
| + unsigned offset = stack_check_table_start();
|
| + // If there is no stack check table, the "table start" will at or after
|
| + // (due to alignment) the end of the instruction stream.
|
| + if (static_cast<int>(offset) < instruction_size()) {
|
| + unsigned* address =
|
| + reinterpret_cast<unsigned*>(instruction_start() + offset);
|
| + unsigned length = address[0];
|
| + PrintF("Stack checks (size = %u)\n", length);
|
| + PrintF("ast_id pc_offset\n");
|
| + for (unsigned i = 0; i < length; ++i) {
|
| + unsigned index = (2 * i) + 1;
|
| + PrintF("%6u %9u\n", address[index], address[index + 1]);
|
| + }
|
| + PrintF("\n");
|
| + }
|
| + }
|
| +
|
| PrintF("RelocInfo (size = %d)\n", relocation_size());
|
| - for (RelocIterator it(this); !it.done(); it.next())
|
| - it.rinfo()->Print();
|
| + for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print();
|
| PrintF("\n");
|
| }
|
| #endif // ENABLE_DISASSEMBLER
|
| @@ -8385,11 +8773,10 @@ MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
|
| }
|
|
|
|
|
| -Object* GlobalObject::GetPropertyCell(LookupResult* result) {
|
| +JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
|
| ASSERT(!HasFastProperties());
|
| Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
|
| - ASSERT(value->IsJSGlobalPropertyCell());
|
| - return value;
|
| + return JSGlobalPropertyCell::cast(value);
|
| }
|
|
|
|
|
| @@ -8648,6 +9035,21 @@ MaybeObject* CompilationCacheTable::PutRegExp(String* src,
|
| }
|
|
|
|
|
| +void CompilationCacheTable::Remove(Object* value) {
|
| + Object* null_value = GetHeap()->null_value();
|
| + for (int entry = 0, size = Capacity(); entry < size; entry++) {
|
| + int entry_index = EntryToIndex(entry);
|
| + int value_index = entry_index + 1;
|
| + if (get(value_index) == value) {
|
| + fast_set(this, entry_index, null_value);
|
| + fast_set(this, value_index, null_value);
|
| + ElementRemoved();
|
| + }
|
| + }
|
| + return;
|
| +}
|
| +
|
| +
|
| // SymbolsKey used for HashTable where key is array of symbols.
|
| class SymbolsKey : public HashTableKey {
|
| public:
|
|
|