Minor bugfixes and optimizations.
Added command line debugger to D8 shell.
Fixed subtle bug that caused the wrong 'this' to be used when calling a caught function in a catch clause.
Inline array loads within loops directly in the code instead of
git-svn-id: http://v8.googlecode.com/svn/trunk@1031 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/runtime.cc b/src/runtime.cc
index 8c3d043..931c2a0 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -919,6 +919,18 @@
}
+static Object* Runtime_FunctionIsAPIFunction(Arguments args) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 1);
+
+ CONVERT_CHECKED(JSFunction, f, args[0]);
+ // The function_data field of the shared function info is used exclusively by
+ // the API.
+ return !f->shared()->function_data()->IsUndefined() ? Heap::true_value()
+ : Heap::false_value();
+}
+
+
static Object* Runtime_SetCode(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 2);
@@ -1049,7 +1061,7 @@
};
// buffers reused by BoyerMoore
-static int bad_char_occurence[kBMAlphabetSize];
+static int bad_char_occurrence[kBMAlphabetSize];
static BMGoodSuffixBuffers bmgs_buffers;
// Compute the bad-char table for Boyer-Moore in the static buffer.
@@ -1062,16 +1074,16 @@
int table_size = (sizeof(pchar) == 1) ? String::kMaxAsciiCharCode + 1
: kBMAlphabetSize;
if (start == 0) { // All patterns less than kBMMaxShift in length.
- memset(bad_char_occurence, -1, table_size * sizeof(*bad_char_occurence));
+ memset(bad_char_occurrence, -1, table_size * sizeof(*bad_char_occurrence));
} else {
for (int i = 0; i < table_size; i++) {
- bad_char_occurence[i] = start - 1;
+ bad_char_occurrence[i] = start - 1;
}
}
for (int i = start; i < pattern.length() - 1; i++) {
pchar c = pattern[i];
int bucket = (sizeof(pchar) ==1) ? c : c % kBMAlphabetSize;
- bad_char_occurence[bucket] = i;
+ bad_char_occurrence[bucket] = i;
}
}
@@ -1126,28 +1138,27 @@
}
template <typename schar, typename pchar>
-static inline int CharOccurence(int char_code) {
+static inline int CharOccurrence(int char_code) {
if (sizeof(schar) == 1) {
- return bad_char_occurence[char_code];
+ return bad_char_occurrence[char_code];
}
if (sizeof(pchar) == 1) {
if (char_code > String::kMaxAsciiCharCode) {
return -1;
}
- return bad_char_occurence[char_code];
+ return bad_char_occurrence[char_code];
}
- return bad_char_occurence[char_code % kBMAlphabetSize];
+ return bad_char_occurrence[char_code % kBMAlphabetSize];
}
-// Restricted simplified Boyer-Moore string matching. Restricts tables to a
-// suffix of long pattern strings and handles only equivalence classes
-// of the full alphabet. This allows us to ensure that tables take only
-// a fixed amount of space.
+// Restricted simplified Boyer-Moore string matching.
+// Uses only the bad-shift table of Boyer-Moore and only uses it
+// for the character compared to the last character of the needle.
template <typename schar, typename pchar>
-static int BoyerMooreSimplified(Vector<const schar> subject,
- Vector<const pchar> pattern,
- int start_index,
- bool* complete) {
+static int BoyerMooreHorsepool(Vector<const schar> subject,
+ Vector<const pchar> pattern,
+ int start_index,
+ bool* complete) {
int n = subject.length();
int m = pattern.length();
// Only preprocess at most kBMMaxShift last characters of pattern.
@@ -1158,12 +1169,13 @@
int badness = -m; // How bad we are doing without a good-suffix table.
int idx; // No matches found prior to this index.
pchar last_char = pattern[m - 1];
+ int last_char_shift = m - 1 - CharOccurrence<schar, pchar>(last_char);
// Perform search
for (idx = start_index; idx <= n - m;) {
int j = m - 1;
int c;
while (last_char != (c = subject[idx + j])) {
- int bc_occ = CharOccurence<schar, pchar>(c);
+ int bc_occ = CharOccurrence<schar, pchar>(c);
int shift = j - bc_occ;
idx += shift;
badness += 1 - shift; // at most zero, so badness cannot increase.
@@ -1173,19 +1185,17 @@
}
}
j--;
- while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--;
+ while (j >= 0 && pattern[j] == (subject[idx + j])) j--;
if (j < 0) {
*complete = true;
return idx;
} else {
- int bc_occ = CharOccurence<schar, pchar>(c);
- int shift = bc_occ < j ? j - bc_occ : 1;
- idx += shift;
+ idx += last_char_shift;
// Badness increases by the number of characters we have
// checked, and decreases by the number of characters we
// can skip by shifting. It's a measure of how we are doing
// compared to reading each character exactly once.
- badness += (m - j) - shift;
+ badness += (m - j) - last_char_shift;
if (badness > 0) {
*complete = false;
return idx;
@@ -1214,7 +1224,7 @@
int j = m - 1;
schar c;
while (last_char != (c = subject[idx + j])) {
- int shift = j - CharOccurence<schar, pchar>(c);
+ int shift = j - CharOccurrence<schar, pchar>(c);
idx += shift;
if (idx > n - m) {
return -1;
@@ -1225,12 +1235,15 @@
return idx;
} else if (j < start) {
// we have matched more than our tables allow us to be smart about.
- idx += 1;
+ // Fall back on BMH shift.
+ idx += m - 1 - CharOccurrence<schar, pchar>(last_char);
} else {
int gs_shift = bmgs_buffers.shift(j + 1); // Good suffix shift.
- int bc_occ = CharOccurence<schar, pchar>(c);
+ int bc_occ = CharOccurrence<schar, pchar>(c);
int shift = j - bc_occ; // Bad-char shift.
- shift = (gs_shift > shift) ? gs_shift : shift;
+ if (gs_shift > shift) {
+ shift = gs_shift;
+ }
idx += shift;
}
} while (idx <= n - m);
@@ -1274,7 +1287,7 @@
badness++;
if (badness > 0) {
*complete = false;
- return (i);
+ return i;
}
if (subject[i] != pattern_first_char) continue;
int j = 1;
@@ -1345,7 +1358,7 @@
bool complete;
int idx = SimpleIndexOf(sub, pat, start_index, &complete);
if (complete) return idx;
- idx = BoyerMooreSimplified(sub, pat, idx, &complete);
+ idx = BoyerMooreHorsepool(sub, pat, idx, &complete);
if (complete) return idx;
return BoyerMooreIndexOf(sub, pat, idx);
}
@@ -3310,16 +3323,10 @@
if (constructor->IsJSFunction()) {
JSFunction* function = JSFunction::cast(constructor);
- // Handle steping into constructors.
+ // Handle steping into constructors if step into is active.
if (Debug::StepInActive()) {
- StackFrameIterator it;
- it.Advance();
- ASSERT(it.frame()->is_construct());
- it.Advance();
- if (it.frame()->fp() == Debug::step_in_fp()) {
- HandleScope scope;
- Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
- }
+ HandleScope scope;
+ Debug::HandleStepIn(Handle<JSFunction>(function), 0, true);
}
if (function->has_initial_map() &&
@@ -3415,19 +3422,15 @@
return result; // non-failure
}
-
-static Object* Runtime_PushContext(Arguments args) {
- NoHandleAllocation ha;
- ASSERT(args.length() == 1);
-
+static Object* PushContextHelper(Object* object, bool is_catch_context) {
// Convert the object to a proper JavaScript object.
- Object* object = args[0];
- if (!object->IsJSObject()) {
- object = object->ToObject();
- if (object->IsFailure()) {
- if (!Failure::cast(object)->IsInternalError()) return object;
+ Object* js_object = object;
+ if (!js_object->IsJSObject()) {
+ js_object = js_object->ToObject();
+ if (js_object->IsFailure()) {
+ if (!Failure::cast(js_object)->IsInternalError()) return js_object;
HandleScope scope;
- Handle<Object> handle(args[0]);
+ Handle<Object> handle(object);
Handle<Object> result =
Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
return Top::Throw(*result);
@@ -3435,15 +3438,32 @@
}
Object* result =
- Heap::AllocateWithContext(Top::context(), JSObject::cast(object));
+ Heap::AllocateWithContext(Top::context(),
+ JSObject::cast(js_object),
+ is_catch_context);
if (result->IsFailure()) return result;
- Top::set_context(Context::cast(result));
+ Context* context = Context::cast(result);
+ Top::set_context(context);
return result;
}
+static Object* Runtime_PushContext(Arguments args) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 1);
+ return PushContextHelper(args[0], false);
+}
+
+
+static Object* Runtime_PushCatchContext(Arguments args) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 1);
+ return PushContextHelper(args[0], true);
+}
+
+
static Object* Runtime_LookupContext(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 2);
@@ -3541,9 +3561,14 @@
if (!holder.is_null() && holder->IsJSObject()) {
ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
JSObject* object = JSObject::cast(*holder);
- JSObject* receiver = (object->IsGlobalObject())
- ? GlobalObject::cast(object)->global_receiver()
- : ComputeReceiverForNonGlobal(object);
+ JSObject* receiver;
+ if (object->IsGlobalObject()) {
+ receiver = GlobalObject::cast(object)->global_receiver();
+ } else if (context->is_exception_holder(*holder)) {
+ receiver = Top::context()->global()->global_receiver();
+ } else {
+ receiver = ComputeReceiverForNonGlobal(object);
+ }
// No need to unhole the value here. This is taken care of by the
// GetProperty function.
Object* value = object->GetProperty(*name);
@@ -3664,61 +3689,9 @@
}
-static Object* RuntimePreempt(Arguments args) {
- // Clear the preempt request flag.
- StackGuard::Continue(PREEMPT);
-
- ContextSwitcher::PreemptionReceived();
-
- {
- v8::Unlocker unlocker;
- Thread::YieldCPU();
- }
-
- return Heap::undefined_value();
-}
-
-
-static Object* DebugBreakHelper() {
- // Just continue if breaks are disabled.
- if (Debug::disable_break()) {
- return Heap::undefined_value();
- }
-
- // Don't break in system functions. If the current function is
- // either in the builtins object of some context or is in the debug
- // context just return with the debug break stack guard active.
- JavaScriptFrameIterator it;
- JavaScriptFrame* frame = it.frame();
- Object* fun = frame->function();
- if (fun->IsJSFunction()) {
- GlobalObject* global = JSFunction::cast(fun)->context()->global();
- if (global->IsJSBuiltinsObject() || Debug::IsDebugGlobal(global)) {
- return Heap::undefined_value();
- }
- }
-
- // Clear the debug request flag.
- StackGuard::Continue(DEBUGBREAK);
-
- HandleScope scope;
- // Enter the debugger. Just continue if we fail to enter the debugger.
- EnterDebugger debugger;
- if (debugger.FailedToEnter()) {
- return Heap::undefined_value();
- }
-
- // Notify the debug event listeners.
- Debugger::OnDebugBreak(Factory::undefined_value());
-
- // Return to continue execution.
- return Heap::undefined_value();
-}
-
-
static Object* Runtime_DebugBreak(Arguments args) {
ASSERT(args.length() == 0);
- return DebugBreakHelper();
+ return Execution::DebugBreakHelper();
}
@@ -3728,16 +3701,7 @@
// First check if this is a real stack overflow.
if (StackGuard::IsStackOverflow()) return Runtime_StackOverflow(args);
- // If not real stack overflow the stack guard was used to interrupt
- // execution for another purpose.
- if (StackGuard::IsDebugBreak()) DebugBreakHelper();
- if (StackGuard::IsPreempted()) RuntimePreempt(args);
- if (StackGuard::IsInterrupted()) {
- // interrupt
- StackGuard::Continue(INTERRUPT);
- return Top::StackOverflow();
- }
- return Heap::undefined_value();
+ return Execution::HandleStackGuardInterrupt();
}
@@ -5268,7 +5232,9 @@
Handle<Context> previous(context_chain->previous());
Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
return Factory::NewWithContext(
- CopyWithContextChain(function_context, previous), extension);
+ CopyWithContextChain(function_context, previous),
+ extension,
+ context_chain->IsCatchContext());
}
@@ -5874,6 +5840,16 @@
#endif
+static Object* Runtime_Log(Arguments args) {
+ ASSERT(args.length() == 2);
+ String* format = String::cast(args[0]);
+ Vector<const char> chars = format->ToAsciiVector();
+ JSArray* elms = JSArray::cast(args[1]);
+ Logger::LogRuntime(chars, elms);
+ return Heap::undefined_value();
+}
+
+
static Object* Runtime_IS_VAR(Arguments args) {
UNREACHABLE(); // implemented as macro in the parser
return NULL;