| Index: src/ia32/codegen-ia32.cc
|
| diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
|
| index 9c8573cea0ca1ce76f5c2ec97a412a71ca83397c..c006b869514b21d87c052802db55c5d26bbd55fe 100644
|
| --- a/src/ia32/codegen-ia32.cc
|
| +++ b/src/ia32/codegen-ia32.cc
|
| @@ -9149,7 +9149,8 @@ class DeferredReferenceGetNamedValue: public DeferredCode {
|
| : dst_(dst),
|
| receiver_(receiver),
|
| name_(name),
|
| - is_contextual_(is_contextual) {
|
| + is_contextual_(is_contextual),
|
| + is_dont_delete_(false) {
|
| set_comment(is_contextual
|
| ? "[ DeferredReferenceGetNamedValue (contextual)"
|
| : "[ DeferredReferenceGetNamedValue");
|
| @@ -9159,12 +9160,18 @@ class DeferredReferenceGetNamedValue: public DeferredCode {
|
|
|
| Label* patch_site() { return &patch_site_; }
|
|
|
| + void set_is_dont_delete(bool value) {
|
| + ASSERT(is_contextual_);
|
| + is_dont_delete_ = value;
|
| + }
|
| +
|
| private:
|
| Label patch_site_;
|
| Register dst_;
|
| Register receiver_;
|
| Handle<String> name_;
|
| bool is_contextual_;
|
| + bool is_dont_delete_;
|
| };
|
|
|
|
|
| @@ -9181,8 +9188,8 @@ void DeferredReferenceGetNamedValue::Generate() {
|
| // The call must be followed by:
|
| // - a test eax instruction to indicate that the inobject property
|
| // case was inlined.
|
| - // - a mov ecx instruction to indicate that the contextual property
|
| - // load was inlined.
|
| + // - a mov ecx or mov edx instruction to indicate that the
|
| + // contextual property load was inlined.
|
| //
|
| // Store the delta to the map check instruction here in the test
|
| // instruction. Use masm_-> instead of the __ macro since the
|
| @@ -9191,8 +9198,11 @@ void DeferredReferenceGetNamedValue::Generate() {
|
| // Here we use masm_-> instead of the __ macro because this is the
|
| // instruction that gets patched and coverage code gets in the way.
|
| if (is_contextual_) {
|
| - masm_->mov(ecx, -delta_to_patch_site);
|
| + masm_->mov(is_dont_delete_ ? edx : ecx, -delta_to_patch_site);
|
| __ IncrementCounter(&Counters::named_load_global_inline_miss, 1);
|
| + if (is_dont_delete_) {
|
| + __ IncrementCounter(&Counters::dont_delete_hint_miss, 1);
|
| + }
|
| } else {
|
| masm_->test(eax, Immediate(-delta_to_patch_site));
|
| __ IncrementCounter(&Counters::named_load_inline_miss, 1);
|
| @@ -9436,9 +9446,34 @@ Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
|
| }
|
| __ mov(result.reg(),
|
| FieldOperand(result.reg(), JSGlobalPropertyCell::kValueOffset));
|
| - __ cmp(result.reg(), Factory::the_hole_value());
|
| - deferred->Branch(equal);
|
| + bool is_dont_delete = false;
|
| + if (!info_->closure().is_null()) {
|
| + // When doing lazy compilation we can check if the global cell
|
| + // already exists and use its "don't delete" status as a hint.
|
| + AssertNoAllocation no_gc;
|
| + v8::internal::GlobalObject* global_object =
|
| + info_->closure()->context()->global();
|
| + LookupResult lookup;
|
| + global_object->LocalLookupRealNamedProperty(*name, &lookup);
|
| + if (lookup.IsProperty() && lookup.type() == NORMAL) {
|
| + ASSERT(lookup.holder() == global_object);
|
| + ASSERT(global_object->property_dictionary()->ValueAt(
|
| + lookup.GetDictionaryEntry())->IsJSGlobalPropertyCell());
|
| + is_dont_delete = lookup.IsDontDelete();
|
| + }
|
| + }
|
| + deferred->set_is_dont_delete(is_dont_delete);
|
| + if (!is_dont_delete) {
|
| + __ cmp(result.reg(), Factory::the_hole_value());
|
| + deferred->Branch(equal);
|
| + } else if (FLAG_debug_code) {
|
| + __ cmp(result.reg(), Factory::the_hole_value());
|
| + __ Check(not_equal, "DontDelete cells can't contain the hole");
|
| + }
|
| __ IncrementCounter(&Counters::named_load_global_inline, 1);
|
| + if (is_dont_delete) {
|
| + __ IncrementCounter(&Counters::dont_delete_hint_hit, 1);
|
| + }
|
| } else {
|
| // The initial (invalid) offset has to be large enough to force a 32-bit
|
| // instruction encoding to allow patching with an arbitrary offset. Use
|
|
|