~ubuntu-branches/ubuntu/saucy/nodejs/saucy-proposed

« back to all changes in this revision

Viewing changes to deps/v8/src/liveedit.cc

  • Committer: Package Import Robot
  • Author(s): Jérémy Lal
  • Date: 2013-08-14 00:16:46 UTC
  • mfrom: (7.1.40 sid)
  • Revision ID: package-import@ubuntu.com-20130814001646-bzlysfh8sd6mukbo
Tags: 0.10.15~dfsg1-4
* Update 2005 patch, adding a handful of tests that can fail on
  slow platforms.
* Add 1004 patch to fix test failures when writing NaN to buffer
  on mipsel.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2011 the V8 project authors. All rights reserved.
 
1
// Copyright 2012 the V8 project authors. All rights reserved.
2
2
// Redistribution and use in source and binary forms, with or without
3
3
// modification, are permitted provided that the following conditions are
4
4
// met:
30
30
 
31
31
#include "liveedit.h"
32
32
 
 
33
#include "code-stubs.h"
33
34
#include "compilation-cache.h"
34
35
#include "compiler.h"
35
36
#include "debug.h"
53
54
  // Ignore return value from SetElement. It can only be a failure if there
54
55
  // are element setters causing exceptions and the debugger context has none
55
56
  // of these.
56
 
  Handle<Object> no_failure;
57
 
  no_failure = SetElement(object, index, value, kNonStrictMode);
 
57
  Handle<Object> no_failure =
 
58
      JSObject::SetElement(object, index, value, NONE, kNonStrictMode);
58
59
  ASSERT(!no_failure.is_null());
59
60
  USE(no_failure);
60
61
}
600
601
  PostponeInterruptsScope postpone(isolate);
601
602
 
602
603
  // Build AST.
603
 
  CompilationInfo info(script);
 
604
  CompilationInfoWithZone info(script);
604
605
  info.MarkAsGlobal();
605
 
  if (ParserApi::Parse(&info)) {
 
606
  // Parse and don't allow skipping lazy functions.
 
607
  if (ParserApi::Parse(&info, kNoParsingFlags)) {
606
608
    // Compile the code.
607
609
    LiveEditFunctionTracker tracker(info.isolate(), info.function());
608
610
    if (Compiler::MakeCodeForLiveEdit(&info)) {
633
635
}
634
636
 
635
637
 
 
638
static Handle<SharedFunctionInfo> UnwrapSharedFunctionInfoFromJSValue(
 
639
    Handle<JSValue> jsValue) {
 
640
  Object* shared = jsValue->value();
 
641
  CHECK(shared->IsSharedFunctionInfo());
 
642
  return Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(shared));
 
643
}
 
644
 
 
645
 
 
646
static int GetArrayLength(Handle<JSArray> array) {
 
647
  Object* length = array->length();
 
648
  CHECK(length->IsSmi());
 
649
  return Smi::cast(length)->value();
 
650
}
 
651
 
 
652
 
636
653
// Simple helper class that creates more or less typed structures over
637
654
// JSArray object. This is an adhoc method of passing structures from C++
638
655
// to JavaScript.
668
685
  }
669
686
  int GetSmiValueField(int field_position) {
670
687
    Object* res = GetField(field_position);
 
688
    CHECK(res->IsSmi());
671
689
    return Smi::cast(res)->value();
672
690
  }
673
691
 
712
730
    return this->GetSmiValueField(kParentIndexOffset_);
713
731
  }
714
732
  Handle<Code> GetFunctionCode() {
715
 
    Handle<Object> raw_result = UnwrapJSValue(Handle<JSValue>(
716
 
        JSValue::cast(this->GetField(kCodeOffset_))));
 
733
    Object* element = this->GetField(kCodeOffset_);
 
734
    CHECK(element->IsJSValue());
 
735
    Handle<JSValue> value_wrapper(JSValue::cast(element));
 
736
    Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
 
737
    CHECK(raw_result->IsCode());
717
738
    return Handle<Code>::cast(raw_result);
718
739
  }
719
740
  Handle<Object> GetCodeScopeInfo() {
720
 
    Handle<Object> raw_result = UnwrapJSValue(Handle<JSValue>(
721
 
        JSValue::cast(this->GetField(kCodeScopeInfoOffset_))));
722
 
    return raw_result;
 
741
    Object* element = this->GetField(kCodeScopeInfoOffset_);
 
742
    CHECK(element->IsJSValue());
 
743
    return UnwrapJSValue(Handle<JSValue>(JSValue::cast(element)));
723
744
  }
724
745
  int GetStartPosition() {
725
746
    return this->GetSmiValueField(kStartPositionOffset_);
769
790
  }
770
791
  Handle<SharedFunctionInfo> GetInfo() {
771
792
    Object* element = this->GetField(kSharedInfoOffset_);
 
793
    CHECK(element->IsJSValue());
772
794
    Handle<JSValue> value_wrapper(JSValue::cast(element));
773
 
    Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
774
 
    return Handle<SharedFunctionInfo>::cast(raw_result);
 
795
    return UnwrapSharedFunctionInfoFromJSValue(value_wrapper);
775
796
  }
776
797
 
777
798
 private:
797
818
    HandleScope scope;
798
819
    FunctionInfoWrapper info = FunctionInfoWrapper::Create();
799
820
    info.SetInitialProperties(fun->name(), fun->start_position(),
800
 
                              fun->end_position(), fun->num_parameters(),
 
821
                              fun->end_position(), fun->parameter_count(),
801
822
                              current_parent_index_);
802
823
    current_parent_index_ = len_;
803
824
    SetElementNonStrict(result_, len_, info.GetJSArray());
823
844
 
824
845
  // Saves full information about a function: its code, its scope info
825
846
  // and a SharedFunctionInfo object.
826
 
  void FunctionInfo(Handle<SharedFunctionInfo> shared, Scope* scope) {
 
847
  void FunctionInfo(Handle<SharedFunctionInfo> shared, Scope* scope,
 
848
                    Zone* zone) {
827
849
    if (!shared->IsSharedFunctionInfo()) {
828
850
      return;
829
851
    }
834
856
        Handle<Object>(shared->scope_info()));
835
857
    info.SetSharedFunctionInfo(shared);
836
858
 
837
 
    Handle<Object> scope_info_list(SerializeFunctionScope(scope));
 
859
    Handle<Object> scope_info_list(SerializeFunctionScope(scope, zone));
838
860
    info.SetOuterScopeInfo(scope_info_list);
839
861
  }
840
862
 
841
863
  Handle<JSArray> GetResult() { return result_; }
842
864
 
843
865
 private:
844
 
  Object* SerializeFunctionScope(Scope* scope) {
 
866
  Object* SerializeFunctionScope(Scope* scope, Zone* zone) {
845
867
    HandleScope handle_scope;
846
868
 
847
869
    Handle<JSArray> scope_info_list = FACTORY->NewJSArray(10);
855
877
      return HEAP->undefined_value();
856
878
    }
857
879
    do {
858
 
      ZoneList<Variable*> list(10);
859
 
      outer_scope->CollectUsedVariables(&list);
860
 
      int j = 0;
861
 
      for (int i = 0; i < list.length(); i++) {
862
 
        Variable* var1 = list[i];
863
 
        if (var1->IsContextSlot()) {
864
 
          if (j != i) {
865
 
            list[j] = var1;
866
 
          }
867
 
          j++;
868
 
        }
869
 
      }
 
880
      ZoneList<Variable*> stack_list(outer_scope->StackLocalCount(), zone);
 
881
      ZoneList<Variable*> context_list(outer_scope->ContextLocalCount(), zone);
 
882
      outer_scope->CollectStackAndContextLocals(&stack_list, &context_list);
 
883
      context_list.Sort(&Variable::CompareIndex);
870
884
 
871
 
      // Sort it.
872
 
      for (int k = 1; k < j; k++) {
873
 
        int l = k;
874
 
        for (int m = k + 1; m < j; m++) {
875
 
          if (list[l]->index() > list[m]->index()) {
876
 
            l = m;
877
 
          }
878
 
        }
879
 
        list[k] = list[l];
880
 
      }
881
 
      for (int i = 0; i < j; i++) {
 
885
      for (int i = 0; i < context_list.length(); i++) {
882
886
        SetElementNonStrict(scope_info_list,
883
887
                            scope_info_length,
884
 
                            list[i]->name());
 
888
                            context_list[i]->name());
885
889
        scope_info_length++;
886
890
        SetElementNonStrict(
887
891
            scope_info_list,
888
892
            scope_info_length,
889
 
            Handle<Smi>(Smi::FromInt(list[i]->index())));
 
893
            Handle<Smi>(Smi::FromInt(context_list[i]->index())));
890
894
        scope_info_length++;
891
895
      }
892
896
      SetElementNonStrict(scope_info_list,
909
913
JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script,
910
914
                                     Handle<String> source) {
911
915
  Isolate* isolate = Isolate::Current();
912
 
  ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
913
916
 
914
917
  FunctionInfoListener listener;
915
918
  Handle<Object> original_source = Handle<Object>(script->source());
925
928
 
926
929
void LiveEdit::WrapSharedFunctionInfos(Handle<JSArray> array) {
927
930
  HandleScope scope;
928
 
  int len = Smi::cast(array->length())->value();
 
931
  int len = GetArrayLength(array);
929
932
  for (int i = 0; i < len; i++) {
930
933
    Handle<SharedFunctionInfo> info(
931
934
        SharedFunctionInfo::cast(array->GetElementNoExceptionThrown(i)));
938
941
}
939
942
 
940
943
 
941
 
// Visitor that collects all references to a particular code object,
942
 
// including "CODE_TARGET" references in other code objects.
943
 
// It works in context of ZoneScope.
944
 
class ReferenceCollectorVisitor : public ObjectVisitor {
 
944
// Visitor that finds all references to a particular code object,
 
945
// including "CODE_TARGET" references in other code objects and replaces
 
946
// them on the fly.
 
947
class ReplacingVisitor : public ObjectVisitor {
945
948
 public:
946
 
  explicit ReferenceCollectorVisitor(Code* original)
947
 
    : original_(original), rvalues_(10), reloc_infos_(10), code_entries_(10) {
 
949
  explicit ReplacingVisitor(Code* original, Code* substitution)
 
950
    : original_(original), substitution_(substitution) {
948
951
  }
949
952
 
950
953
  virtual void VisitPointers(Object** start, Object** end) {
951
954
    for (Object** p = start; p < end; p++) {
952
955
      if (*p == original_) {
953
 
        rvalues_.Add(p);
 
956
        *p = substitution_;
954
957
      }
955
958
    }
956
959
  }
957
960
 
958
961
  virtual void VisitCodeEntry(Address entry) {
959
962
    if (Code::GetObjectFromEntryAddress(entry) == original_) {
960
 
      code_entries_.Add(entry);
 
963
      Address substitution_entry = substitution_->instruction_start();
 
964
      Memory::Address_at(entry) = substitution_entry;
961
965
    }
962
966
  }
963
967
 
964
968
  virtual void VisitCodeTarget(RelocInfo* rinfo) {
965
969
    if (RelocInfo::IsCodeTarget(rinfo->rmode()) &&
966
970
        Code::GetCodeFromTargetAddress(rinfo->target_address()) == original_) {
967
 
      reloc_infos_.Add(*rinfo);
 
971
      Address substitution_entry = substitution_->instruction_start();
 
972
      rinfo->set_target_address(substitution_entry);
968
973
    }
969
974
  }
970
975
 
972
977
    VisitCodeTarget(rinfo);
973
978
  }
974
979
 
975
 
  // Post-visiting method that iterates over all collected references and
976
 
  // modifies them.
977
 
  void Replace(Code* substitution) {
978
 
    for (int i = 0; i < rvalues_.length(); i++) {
979
 
      *(rvalues_[i]) = substitution;
980
 
    }
981
 
    Address substitution_entry = substitution->instruction_start();
982
 
    for (int i = 0; i < reloc_infos_.length(); i++) {
983
 
      reloc_infos_[i].set_target_address(substitution_entry);
984
 
    }
985
 
    for (int i = 0; i < code_entries_.length(); i++) {
986
 
      Address entry = code_entries_[i];
987
 
      Memory::Address_at(entry) = substitution_entry;
988
 
    }
989
 
  }
990
 
 
991
980
 private:
992
981
  Code* original_;
993
 
  ZoneList<Object**> rvalues_;
994
 
  ZoneList<RelocInfo> reloc_infos_;
995
 
  ZoneList<Address> code_entries_;
 
982
  Code* substitution_;
996
983
};
997
984
 
998
985
 
999
986
// Finds all references to original and replaces them with substitution.
1000
 
static void ReplaceCodeObject(Code* original, Code* substitution) {
1001
 
  ASSERT(!HEAP->InNewSpace(substitution));
 
987
static void ReplaceCodeObject(Handle<Code> original,
 
988
                              Handle<Code> substitution) {
 
989
  // Perform a full GC in order to ensure that we are not in the middle of an
 
990
  // incremental marking phase when we are replacing the code object.
 
991
  // Since we are not in an incremental marking phase we can write pointers
 
992
  // to code objects (that are never in new space) without worrying about
 
993
  // write barriers.
 
994
  HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask,
 
995
                          "liveedit.cc ReplaceCodeObject");
 
996
 
 
997
  ASSERT(!HEAP->InNewSpace(*substitution));
1002
998
 
1003
999
  AssertNoAllocation no_allocations_please;
1004
1000
 
1005
 
  // A zone scope for ReferenceCollectorVisitor.
1006
 
  ZoneScope scope(Isolate::Current(), DELETE_ON_EXIT);
1007
 
 
1008
 
  ReferenceCollectorVisitor visitor(original);
 
1001
  ReplacingVisitor visitor(*original, *substitution);
1009
1002
 
1010
1003
  // Iterate over all roots. Stack frames may have pointer into original code,
1011
1004
  // so temporary replace the pointers with offset numbers
1012
1005
  // in prologue/epilogue.
1013
 
  {
1014
 
    HEAP->IterateStrongRoots(&visitor, VISIT_ALL);
1015
 
  }
 
1006
  HEAP->IterateRoots(&visitor, VISIT_ALL);
1016
1007
 
1017
1008
  // Now iterate over all pointers of all objects, including code_target
1018
1009
  // implicit pointers.
1020
1011
  for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1021
1012
    obj->Iterate(&visitor);
1022
1013
  }
1023
 
 
1024
 
  visitor.Replace(substitution);
1025
1014
}
1026
1015
 
1027
1016
 
1101
1090
 
1102
1091
  Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
1103
1092
 
 
1093
  HEAP->EnsureHeapIsIterable();
 
1094
 
1104
1095
  if (IsJSFunctionCode(shared_info->code())) {
1105
1096
    Handle<Code> code = compile_info_wrapper.GetFunctionCode();
1106
 
    ReplaceCodeObject(shared_info->code(), *code);
1107
 
    Handle<Object> code_scope_info =  compile_info_wrapper.GetCodeScopeInfo();
 
1097
    ReplaceCodeObject(Handle<Code>(shared_info->code()), code);
 
1098
    Handle<Object> code_scope_info = compile_info_wrapper.GetCodeScopeInfo();
1108
1099
    if (code_scope_info->IsFixedArray()) {
1109
 
      shared_info->set_scope_info(SerializedScopeInfo::cast(*code_scope_info));
 
1100
      shared_info->set_scope_info(ScopeInfo::cast(*code_scope_info));
1110
1101
    }
1111
1102
  }
1112
1103
 
1154
1145
void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper,
1155
1146
                                 Handle<Object> script_handle) {
1156
1147
  Handle<SharedFunctionInfo> shared_info =
1157
 
      Handle<SharedFunctionInfo>::cast(UnwrapJSValue(function_wrapper));
 
1148
      UnwrapSharedFunctionInfoFromJSValue(function_wrapper);
 
1149
  CHECK(script_handle->IsScript() || script_handle->IsUndefined());
1158
1150
  shared_info->set_script(*script_handle);
1159
1151
 
1160
1152
  Isolate::Current()->compilation_cache()->Remove(shared_info);
1173
1165
static int TranslatePosition(int original_position,
1174
1166
                             Handle<JSArray> position_change_array) {
1175
1167
  int position_diff = 0;
1176
 
  int array_len = Smi::cast(position_change_array->length())->value();
 
1168
  int array_len = GetArrayLength(position_change_array);
1177
1169
  // TODO(635): binary search may be used here
1178
1170
  for (int i = 0; i < array_len; i += 3) {
1179
1171
    Object* element = position_change_array->GetElementNoExceptionThrown(i);
 
1172
    CHECK(element->IsSmi());
1180
1173
    int chunk_start = Smi::cast(element)->value();
1181
1174
    if (original_position < chunk_start) {
1182
1175
      break;
1183
1176
    }
1184
1177
    element = position_change_array->GetElementNoExceptionThrown(i + 1);
 
1178
    CHECK(element->IsSmi());
1185
1179
    int chunk_end = Smi::cast(element)->value();
1186
1180
    // Position mustn't be inside a chunk.
1187
1181
    ASSERT(original_position >= chunk_end);
1188
1182
    element = position_change_array->GetElementNoExceptionThrown(i + 2);
 
1183
    CHECK(element->IsSmi());
1189
1184
    int chunk_changed_end = Smi::cast(element)->value();
1190
1185
    position_diff = chunk_changed_end - chunk_end;
1191
1186
  }
1243
1238
      V8::FatalProcessOutOfMemory("RelocInfoBuffer::GrowBuffer");
1244
1239
    }
1245
1240
 
1246
 
    // Setup new buffer.
 
1241
    // Set up new buffer.
1247
1242
    byte* new_buffer = NewArray<byte>(new_buffer_size);
1248
1243
 
1249
1244
    // Copy the data.
1271
1266
 
1272
1267
// Patch positions in code (changes relocation info section) and possibly
1273
1268
// returns new instance of code.
1274
 
static Handle<Code> PatchPositionsInCode(Handle<Code> code,
 
1269
static Handle<Code> PatchPositionsInCode(
 
1270
    Handle<Code> code,
1275
1271
    Handle<JSArray> position_change_array) {
1276
1272
 
1277
1273
  RelocInfoBuffer buffer_writer(code->relocation_size(),
1286
1282
        int new_position = TranslatePosition(position,
1287
1283
                                             position_change_array);
1288
1284
        if (position != new_position) {
1289
 
          RelocInfo info_copy(rinfo->pc(), rinfo->rmode(), new_position);
 
1285
          RelocInfo info_copy(rinfo->pc(), rinfo->rmode(), new_position, NULL);
1290
1286
          buffer_writer.Write(&info_copy);
1291
1287
          continue;
1292
1288
        }
1313
1309
 
1314
1310
MaybeObject* LiveEdit::PatchFunctionPositions(
1315
1311
    Handle<JSArray> shared_info_array, Handle<JSArray> position_change_array) {
1316
 
 
1317
1312
  if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
1318
1313
    return Isolate::Current()->ThrowIllegalOperation();
1319
1314
  }
1333
1328
  info->set_end_position(new_function_end);
1334
1329
  info->set_function_token_position(new_function_token_pos);
1335
1330
 
 
1331
  HEAP->EnsureHeapIsIterable();
 
1332
 
1336
1333
  if (IsJSFunctionCode(info->code())) {
1337
1334
    // Patch relocation info section of the code.
1338
1335
    Handle<Code> patched_code = PatchPositionsInCode(Handle<Code>(info->code()),
1343
1340
      // on stack (it is safe to substitute the code object on stack, because
1344
1341
      // we only change the structure of rinfo and leave instructions
1345
1342
      // untouched).
1346
 
      ReplaceCodeObject(info->code(), *patched_code);
 
1343
      ReplaceCodeObject(Handle<Code>(info->code()), patched_code);
1347
1344
    }
1348
1345
  }
1349
1346
 
1401
1398
    Handle<JSValue> subst_function_wrapper) {
1402
1399
 
1403
1400
  Handle<SharedFunctionInfo> parent_shared =
1404
 
      Handle<SharedFunctionInfo>::cast(UnwrapJSValue(parent_function_wrapper));
 
1401
      UnwrapSharedFunctionInfoFromJSValue(parent_function_wrapper);
1405
1402
  Handle<SharedFunctionInfo> orig_shared =
1406
 
      Handle<SharedFunctionInfo>::cast(UnwrapJSValue(orig_function_wrapper));
 
1403
      UnwrapSharedFunctionInfoFromJSValue(orig_function_wrapper);
1407
1404
  Handle<SharedFunctionInfo> subst_shared =
1408
 
      Handle<SharedFunctionInfo>::cast(UnwrapJSValue(subst_function_wrapper));
 
1405
      UnwrapSharedFunctionInfoFromJSValue(subst_function_wrapper);
1409
1406
 
1410
1407
  for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) {
1411
1408
    if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) {
1428
1425
  Handle<JSFunction> function(
1429
1426
      JSFunction::cast(JavaScriptFrame::cast(frame)->function()));
1430
1427
 
1431
 
  int len = Smi::cast(shared_info_array->length())->value();
 
1428
  int len = GetArrayLength(shared_info_array);
1432
1429
  for (int i = 0; i < len; i++) {
1433
 
    JSValue* wrapper =
1434
 
        JSValue::cast(shared_info_array->GetElementNoExceptionThrown(i));
1435
 
    Handle<SharedFunctionInfo> shared(
1436
 
        SharedFunctionInfo::cast(wrapper->value()));
 
1430
    Object* element = shared_info_array->GetElementNoExceptionThrown(i);
 
1431
    CHECK(element->IsJSValue());
 
1432
    Handle<JSValue> jsvalue(JSValue::cast(element));
 
1433
    Handle<SharedFunctionInfo> shared =
 
1434
        UnwrapSharedFunctionInfoFromJSValue(jsvalue);
1437
1435
 
1438
1436
    if (function->shared() == *shared || IsInlined(*function, *shared)) {
1439
1437
      SetElementNonStrict(result, i, Handle<Smi>(Smi::FromInt(status)));
1487
1485
  // Check the nature of the top frame.
1488
1486
  Isolate* isolate = Isolate::Current();
1489
1487
  Code* pre_top_frame_code = pre_top_frame->LookupCode();
 
1488
  bool frame_has_padding;
1490
1489
  if (pre_top_frame_code->is_inline_cache_stub() &&
1491
1490
      pre_top_frame_code->ic_state() == DEBUG_BREAK) {
1492
1491
    // OK, we can drop inline cache calls.
1493
1492
    *mode = Debug::FRAME_DROPPED_IN_IC_CALL;
 
1493
    frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
1494
1494
  } else if (pre_top_frame_code ==
1495
1495
             isolate->debug()->debug_break_slot()) {
1496
1496
    // OK, we can drop debug break slot.
1497
1497
    *mode = Debug::FRAME_DROPPED_IN_DEBUG_SLOT_CALL;
 
1498
    frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
1498
1499
  } else if (pre_top_frame_code ==
1499
1500
      isolate->builtins()->builtin(
1500
1501
          Builtins::kFrameDropper_LiveEdit)) {
1501
1502
    // OK, we can drop our own code.
1502
 
    *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
 
1503
    pre_top_frame = frames[top_frame_index - 2];
 
1504
    top_frame = frames[top_frame_index - 1];
 
1505
    *mode = Debug::CURRENTLY_SET_MODE;
 
1506
    frame_has_padding = false;
1503
1507
  } else if (pre_top_frame_code ==
1504
1508
      isolate->builtins()->builtin(Builtins::kReturn_DebugBreak)) {
1505
1509
    *mode = Debug::FRAME_DROPPED_IN_RETURN_CALL;
 
1510
    frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
1506
1511
  } else if (pre_top_frame_code->kind() == Code::STUB &&
1507
 
      pre_top_frame_code->major_key()) {
1508
 
    // Entry from our unit tests, it's fine, we support this case.
 
1512
      pre_top_frame_code->major_key() == CodeStub::CEntry) {
 
1513
    // Entry from our unit tests on 'debugger' statement.
 
1514
    // It's fine, we support this case.
1509
1515
    *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
 
1516
    // We don't have a padding from 'debugger' statement call.
 
1517
    // Here the stub is CEntry, it's not debug-only and can't be padded.
 
1518
    // If anyone would complain, a proxy padded stub could be added.
 
1519
    frame_has_padding = false;
 
1520
  } else if (pre_top_frame->type() == StackFrame::ARGUMENTS_ADAPTOR) {
 
1521
    // This must be adaptor that remain from the frame dropping that
 
1522
    // is still on stack. A frame dropper frame must be above it.
 
1523
    ASSERT(frames[top_frame_index - 2]->LookupCode() ==
 
1524
        isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit));
 
1525
    pre_top_frame = frames[top_frame_index - 3];
 
1526
    top_frame = frames[top_frame_index - 2];
 
1527
    *mode = Debug::CURRENTLY_SET_MODE;
 
1528
    frame_has_padding = false;
1510
1529
  } else {
1511
1530
    return "Unknown structure of stack above changing function";
1512
1531
  }
1516
1535
      - Debug::kFrameDropperFrameSize * kPointerSize  // Size of the new frame.
1517
1536
      + kPointerSize;  // Bigger address end is exclusive.
1518
1537
 
 
1538
  Address* top_frame_pc_address = top_frame->pc_address();
 
1539
 
 
1540
  // top_frame may be damaged below this point. Do not used it.
 
1541
  ASSERT(!(top_frame = NULL));
 
1542
 
1519
1543
  if (unused_stack_top > unused_stack_bottom) {
1520
 
    return "Not enough space for frame dropper frame";
 
1544
    if (frame_has_padding) {
 
1545
      int shortage_bytes =
 
1546
          static_cast<int>(unused_stack_top - unused_stack_bottom);
 
1547
 
 
1548
      Address padding_start = pre_top_frame->fp() -
 
1549
          Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize;
 
1550
 
 
1551
      Address padding_pointer = padding_start;
 
1552
      Smi* padding_object =
 
1553
          Smi::FromInt(Debug::FramePaddingLayout::kPaddingValue);
 
1554
      while (Memory::Object_at(padding_pointer) == padding_object) {
 
1555
        padding_pointer -= kPointerSize;
 
1556
      }
 
1557
      int padding_counter =
 
1558
          Smi::cast(Memory::Object_at(padding_pointer))->value();
 
1559
      if (padding_counter * kPointerSize < shortage_bytes) {
 
1560
        return "Not enough space for frame dropper frame "
 
1561
            "(even with padding frame)";
 
1562
      }
 
1563
      Memory::Object_at(padding_pointer) =
 
1564
          Smi::FromInt(padding_counter - shortage_bytes / kPointerSize);
 
1565
 
 
1566
      StackFrame* pre_pre_frame = frames[top_frame_index - 2];
 
1567
 
 
1568
      memmove(padding_start + kPointerSize - shortage_bytes,
 
1569
          padding_start + kPointerSize,
 
1570
          Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize);
 
1571
 
 
1572
      pre_top_frame->UpdateFp(pre_top_frame->fp() - shortage_bytes);
 
1573
      pre_pre_frame->SetCallerFp(pre_top_frame->fp());
 
1574
      unused_stack_top -= shortage_bytes;
 
1575
 
 
1576
      STATIC_ASSERT(sizeof(Address) == kPointerSize);
 
1577
      top_frame_pc_address -= shortage_bytes / kPointerSize;
 
1578
    } else {
 
1579
      return "Not enough space for frame dropper frame";
 
1580
    }
1521
1581
  }
1522
1582
 
1523
1583
  // Committing now. After this point we should return only NULL value.
1527
1587
  ASSERT(!FixTryCatchHandler(pre_top_frame, bottom_js_frame));
1528
1588
 
1529
1589
  Handle<Code> code = Isolate::Current()->builtins()->FrameDropper_LiveEdit();
1530
 
  top_frame->set_pc(code->entry());
 
1590
  *top_frame_pc_address = code->entry();
1531
1591
  pre_top_frame->SetCallerFp(bottom_js_frame->fp());
1532
1592
 
1533
1593
  *restarter_frame_function_pointer =
1549
1609
  return !frame->is_exit();
1550
1610
}
1551
1611
 
1552
 
// Fills result array with statuses of functions. Modifies the stack
1553
 
// removing all listed function if possible and if do_drop is true.
1554
 
static const char* DropActivationsInActiveThread(
1555
 
    Handle<JSArray> shared_info_array, Handle<JSArray> result, bool do_drop) {
 
1612
 
 
1613
// Describes a set of call frames that execute any of listed functions.
 
1614
// Finding no such frames does not mean error.
 
1615
class MultipleFunctionTarget {
 
1616
 public:
 
1617
  MultipleFunctionTarget(Handle<JSArray> shared_info_array,
 
1618
      Handle<JSArray> result)
 
1619
      : m_shared_info_array(shared_info_array),
 
1620
        m_result(result) {}
 
1621
  bool MatchActivation(StackFrame* frame,
 
1622
      LiveEdit::FunctionPatchabilityStatus status) {
 
1623
    return CheckActivation(m_shared_info_array, m_result, frame, status);
 
1624
  }
 
1625
  const char* GetNotFoundMessage() {
 
1626
    return NULL;
 
1627
  }
 
1628
 private:
 
1629
  Handle<JSArray> m_shared_info_array;
 
1630
  Handle<JSArray> m_result;
 
1631
};
 
1632
 
 
1633
// Drops all call frame matched by target and all frames above them.
 
1634
template<typename TARGET>
 
1635
static const char* DropActivationsInActiveThreadImpl(
 
1636
    TARGET& target, bool do_drop, Zone* zone) {
1556
1637
  Isolate* isolate = Isolate::Current();
1557
1638
  Debug* debug = isolate->debug();
1558
 
  ZoneScope scope(isolate, DELETE_ON_EXIT);
1559
 
  Vector<StackFrame*> frames = CreateStackMap();
 
1639
  ZoneScope scope(zone, DELETE_ON_EXIT);
 
1640
  Vector<StackFrame*> frames = CreateStackMap(zone);
1560
1641
 
1561
 
  int array_len = Smi::cast(shared_info_array->length())->value();
1562
1642
 
1563
1643
  int top_frame_index = -1;
1564
1644
  int frame_index = 0;
1568
1648
      top_frame_index = frame_index;
1569
1649
      break;
1570
1650
    }
1571
 
    if (CheckActivation(shared_info_array, result, frame,
1572
 
                        LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
 
1651
    if (target.MatchActivation(
 
1652
            frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
1573
1653
      // We are still above break_frame. It is not a target frame,
1574
1654
      // it is a problem.
1575
1655
      return "Debugger mark-up on stack is not found";
1578
1658
 
1579
1659
  if (top_frame_index == -1) {
1580
1660
    // We haven't found break frame, but no function is blocking us anyway.
1581
 
    return NULL;
 
1661
    return target.GetNotFoundMessage();
1582
1662
  }
1583
1663
 
1584
1664
  bool target_frame_found = false;
1591
1671
      c_code_found = true;
1592
1672
      break;
1593
1673
    }
1594
 
    if (CheckActivation(shared_info_array, result, frame,
1595
 
                        LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
 
1674
    if (target.MatchActivation(
 
1675
            frame, LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
1596
1676
      target_frame_found = true;
1597
1677
      bottom_js_frame_index = frame_index;
1598
1678
    }
1604
1684
    for (; frame_index < frames.length(); frame_index++) {
1605
1685
      StackFrame* frame = frames[frame_index];
1606
1686
      if (frame->is_java_script()) {
1607
 
        if (CheckActivation(shared_info_array, result, frame,
1608
 
                            LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
 
1687
        if (target.MatchActivation(
 
1688
                frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
1609
1689
          // Cannot drop frame under C frames.
1610
1690
          return NULL;
1611
1691
        }
1620
1700
 
1621
1701
  if (!target_frame_found) {
1622
1702
    // Nothing to drop.
1623
 
    return NULL;
 
1703
    return target.GetNotFoundMessage();
1624
1704
  }
1625
1705
 
1626
1706
  Debug::FrameDropMode drop_mode = Debug::FRAMES_UNTOUCHED;
1643
1723
  }
1644
1724
  debug->FramesHaveBeenDropped(new_id, drop_mode,
1645
1725
                               restarter_frame_function_pointer);
 
1726
  return NULL;
 
1727
}
 
1728
 
 
1729
// Fills result array with statuses of functions. Modifies the stack
 
1730
// removing all listed function if possible and if do_drop is true.
 
1731
static const char* DropActivationsInActiveThread(
 
1732
    Handle<JSArray> shared_info_array, Handle<JSArray> result, bool do_drop,
 
1733
    Zone* zone) {
 
1734
  MultipleFunctionTarget target(shared_info_array, result);
 
1735
 
 
1736
  const char* message =
 
1737
      DropActivationsInActiveThreadImpl(target, do_drop, zone);
 
1738
  if (message) {
 
1739
    return message;
 
1740
  }
 
1741
 
 
1742
  int array_len = GetArrayLength(shared_info_array);
1646
1743
 
1647
1744
  // Replace "blocked on active" with "replaced on active" status.
1648
1745
  for (int i = 0; i < array_len; i++) {
1683
1780
 
1684
1781
 
1685
1782
Handle<JSArray> LiveEdit::CheckAndDropActivations(
1686
 
    Handle<JSArray> shared_info_array, bool do_drop) {
1687
 
  int len = Smi::cast(shared_info_array->length())->value();
 
1783
    Handle<JSArray> shared_info_array, bool do_drop, Zone* zone) {
 
1784
  int len = GetArrayLength(shared_info_array);
1688
1785
 
1689
1786
  Handle<JSArray> result = FACTORY->NewJSArray(len);
1690
1787
 
1708
1805
 
1709
1806
  // Try to drop activations from the current stack.
1710
1807
  const char* error_message =
1711
 
      DropActivationsInActiveThread(shared_info_array, result, do_drop);
 
1808
      DropActivationsInActiveThread(shared_info_array, result, do_drop, zone);
1712
1809
  if (error_message != NULL) {
1713
1810
    // Add error message as an array extra element.
1714
1811
    Vector<const char> vector_message(error_message, StrLength(error_message));
1719
1816
}
1720
1817
 
1721
1818
 
 
1819
// Describes a single callframe a target. Not finding this frame
 
1820
// means an error.
 
1821
class SingleFrameTarget {
 
1822
 public:
 
1823
  explicit SingleFrameTarget(JavaScriptFrame* frame)
 
1824
      : m_frame(frame),
 
1825
        m_saved_status(LiveEdit::FUNCTION_AVAILABLE_FOR_PATCH) {}
 
1826
 
 
1827
  bool MatchActivation(StackFrame* frame,
 
1828
      LiveEdit::FunctionPatchabilityStatus status) {
 
1829
    if (frame->fp() == m_frame->fp()) {
 
1830
      m_saved_status = status;
 
1831
      return true;
 
1832
    }
 
1833
    return false;
 
1834
  }
 
1835
  const char* GetNotFoundMessage() {
 
1836
    return "Failed to found requested frame";
 
1837
  }
 
1838
  LiveEdit::FunctionPatchabilityStatus saved_status() {
 
1839
    return m_saved_status;
 
1840
  }
 
1841
 private:
 
1842
  JavaScriptFrame* m_frame;
 
1843
  LiveEdit::FunctionPatchabilityStatus m_saved_status;
 
1844
};
 
1845
 
 
1846
 
 
1847
// Finds a drops required frame and all frames above.
 
1848
// Returns error message or NULL.
 
1849
const char* LiveEdit::RestartFrame(JavaScriptFrame* frame, Zone* zone) {
 
1850
  SingleFrameTarget target(frame);
 
1851
 
 
1852
  const char* result = DropActivationsInActiveThreadImpl(target, true, zone);
 
1853
  if (result != NULL) {
 
1854
    return result;
 
1855
  }
 
1856
  if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE) {
 
1857
    return "Function is blocked under native code";
 
1858
  }
 
1859
  return NULL;
 
1860
}
 
1861
 
 
1862
 
1722
1863
LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
1723
1864
                                                 FunctionLiteral* fun)
1724
1865
    : isolate_(isolate) {
1736
1877
 
1737
1878
 
1738
1879
void LiveEditFunctionTracker::RecordFunctionInfo(
1739
 
    Handle<SharedFunctionInfo> info, FunctionLiteral* lit) {
 
1880
    Handle<SharedFunctionInfo> info, FunctionLiteral* lit,
 
1881
    Zone* zone) {
1740
1882
  if (isolate_->active_function_info_listener() != NULL) {
1741
 
    isolate_->active_function_info_listener()->FunctionInfo(info, lit->scope());
 
1883
    isolate_->active_function_info_listener()->FunctionInfo(info, lit->scope(),
 
1884
                                                            zone);
1742
1885
  }
1743
1886
}
1744
1887
 
1767
1910
 
1768
1911
 
1769
1912
void LiveEditFunctionTracker::RecordFunctionInfo(
1770
 
    Handle<SharedFunctionInfo> info, FunctionLiteral* lit) {
 
1913
    Handle<SharedFunctionInfo> info, FunctionLiteral* lit,
 
1914
    Zone* zone) {
1771
1915
}
1772
1916
 
1773
1917