| Index: src/runtime.cc
|
| ===================================================================
|
| --- src/runtime.cc (revision 3935)
|
| +++ src/runtime.cc (working copy)
|
| @@ -1208,17 +1208,6 @@
|
| }
|
|
|
|
|
| -static Object* Runtime_TransformToFastProperties(Arguments args) {
|
| - HandleScope scope;
|
| - ASSERT(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(JSObject, object, 0);
|
| - if (!object->HasFastProperties() && !object->IsGlobalObject()) {
|
| - TransformToFastProperties(object, 0);
|
| - }
|
| - return *object;
|
| -}
|
| -
|
| -
|
| static Object* Runtime_RegExpExec(Arguments args) {
|
| HandleScope scope;
|
| ASSERT(args.length() == 4);
|
| @@ -2287,6 +2276,20 @@
|
| return -1;
|
| }
|
|
|
| +
|
| +template <typename schar>
|
| +static int SingleCharLastIndexOf(Vector<const schar> string,
|
| + schar pattern_char,
|
| + int start_index) {
|
| + for (int i = start_index; i >= 0; i--) {
|
| + if (pattern_char == string[i]) {
|
| + return i;
|
| + }
|
| + }
|
| + return -1;
|
| +}
|
| +
|
| +
|
| // Trivial string search for shorter strings.
|
| // On return, if "complete" is set to true, the return value is the
|
| // final result of searching for the patter in the subject.
|
| @@ -2363,7 +2366,7 @@
|
| // We have an ASCII haystack and a non-ASCII needle. Check if there
|
| // really is a non-ASCII character in the needle and bail out if there
|
| // is.
|
| - if (sizeof(pchar) > 1 && sizeof(schar) == 1) {
|
| + if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
|
| for (int i = 0; i < pat.length(); i++) {
|
| uc16 c = pat[i];
|
| if (c > String::kMaxAsciiCharCode) {
|
| @@ -2466,39 +2469,115 @@
|
| }
|
|
|
|
|
| +template <typename schar, typename pchar>
|
| +static int StringMatchBackwards(Vector<const schar> sub,
|
| + Vector<const pchar> pat,
|
| + int idx) {
|
| + ASSERT(pat.length() >= 1);
|
| + ASSERT(idx + pat.length() <= sub.length());
|
| +
|
| + if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
|
| + for (int i = 0; i < pat.length(); i++) {
|
| + uc16 c = pat[i];
|
| + if (c > String::kMaxAsciiCharCode) {
|
| + return -1;
|
| + }
|
| + }
|
| + }
|
| +
|
| + pchar pattern_first_char = pat[0];
|
| + for (int i = idx; i >= 0; i--) {
|
| + if (sub[i] != pattern_first_char) continue;
|
| + int j = 1;
|
| + while (j < pat.length()) {
|
| + if (pat[j] != sub[i+j]) {
|
| + break;
|
| + }
|
| + j++;
|
| + }
|
| + if (j == pat.length()) {
|
| + return i;
|
| + }
|
| + }
|
| + return -1;
|
| +}
|
| +
|
| static Object* Runtime_StringLastIndexOf(Arguments args) {
|
| - NoHandleAllocation ha;
|
| + HandleScope scope; // create a new handle scope
|
| ASSERT(args.length() == 3);
|
|
|
| - CONVERT_CHECKED(String, sub, args[0]);
|
| - CONVERT_CHECKED(String, pat, args[1]);
|
| + CONVERT_ARG_CHECKED(String, sub, 0);
|
| + CONVERT_ARG_CHECKED(String, pat, 1);
|
| +
|
| Object* index = args[2];
|
| -
|
| - sub->TryFlattenIfNotFlat();
|
| - pat->TryFlattenIfNotFlat();
|
| -
|
| uint32_t start_index;
|
| if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
|
|
|
| - uint32_t pattern_length = pat->length();
|
| + uint32_t pat_length = pat->length();
|
| uint32_t sub_length = sub->length();
|
|
|
| - if (start_index + pattern_length > sub_length) {
|
| - start_index = sub_length - pattern_length;
|
| + if (start_index + pat_length > sub_length) {
|
| + start_index = sub_length - pat_length;
|
| }
|
|
|
| - for (int i = start_index; i >= 0; i--) {
|
| - bool found = true;
|
| - for (uint32_t j = 0; j < pattern_length; j++) {
|
| - if (sub->Get(i + j) != pat->Get(j)) {
|
| - found = false;
|
| - break;
|
| + if (pat_length == 0) {
|
| + return Smi::FromInt(start_index);
|
| + }
|
| +
|
| + if (!sub->IsFlat()) {
|
| + FlattenString(sub);
|
| + }
|
| +
|
| + if (pat_length == 1) {
|
| + AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
|
| + if (sub->IsAsciiRepresentation()) {
|
| + uc16 pchar = pat->Get(0);
|
| + if (pchar > String::kMaxAsciiCharCode) {
|
| + return Smi::FromInt(-1);
|
| }
|
| + return Smi::FromInt(SingleCharLastIndexOf(sub->ToAsciiVector(),
|
| + static_cast<char>(pat->Get(0)),
|
| + start_index));
|
| + } else {
|
| + return Smi::FromInt(SingleCharLastIndexOf(sub->ToUC16Vector(),
|
| + pat->Get(0),
|
| + start_index));
|
| }
|
| - if (found) return Smi::FromInt(i);
|
| }
|
|
|
| - return Smi::FromInt(-1);
|
| + if (!pat->IsFlat()) {
|
| + FlattenString(pat);
|
| + }
|
| +
|
| + AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
|
| +
|
| + int position = -1;
|
| +
|
| + if (pat->IsAsciiRepresentation()) {
|
| + Vector<const char> pat_vector = pat->ToAsciiVector();
|
| + if (sub->IsAsciiRepresentation()) {
|
| + position = StringMatchBackwards(sub->ToAsciiVector(),
|
| + pat_vector,
|
| + start_index);
|
| + } else {
|
| + position = StringMatchBackwards(sub->ToUC16Vector(),
|
| + pat_vector,
|
| + start_index);
|
| + }
|
| + } else {
|
| + Vector<const uc16> pat_vector = pat->ToUC16Vector();
|
| + if (sub->IsAsciiRepresentation()) {
|
| + position = StringMatchBackwards(sub->ToAsciiVector(),
|
| + pat_vector,
|
| + start_index);
|
| + } else {
|
| + position = StringMatchBackwards(sub->ToUC16Vector(),
|
| + pat_vector,
|
| + start_index);
|
| + }
|
| + }
|
| +
|
| + return Smi::FromInt(position);
|
| }
|
|
|
|
|
| @@ -2906,7 +2985,7 @@
|
| // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
|
| // delete it to avoid running into trouble in DefineAccessor, which
|
| // handles this incorrectly if the property is readonly (does nothing)
|
| - if (result.IsValid() &&
|
| + if (result.IsProperty() &&
|
| (result.type() == FIELD || result.type() == NORMAL
|
| || result.type() == CONSTANT_FUNCTION)) {
|
| obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
|
| @@ -2937,12 +3016,14 @@
|
| // correctly in the case where a property is a field and is reset with
|
| // new attributes.
|
| if (result.IsProperty() && attr != result.GetAttributes()) {
|
| - PropertyDetails details = PropertyDetails(attr, NORMAL);
|
| // New attributes - normalize to avoid writing to instance descriptor
|
| - js_object->NormalizeProperties(KEEP_INOBJECT_PROPERTIES, 0);
|
| - return js_object->SetNormalizedProperty(*name, *obj_value, details);
|
| + js_object->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
|
| + // Use IgnoreAttributes version since a readonly property may be
|
| + // overridden and SetProperty does not allow this.
|
| + return js_object->IgnoreAttributesAndSetLocalProperty(*name,
|
| + *obj_value,
|
| + attr);
|
| }
|
| -
|
| return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
|
| }
|
|
|
| @@ -2969,8 +3050,6 @@
|
| // Check if the given key is an array index.
|
| uint32_t index;
|
| if (Array::IndexFromObject(*key, &index)) {
|
| - ASSERT(attr == NONE);
|
| -
|
| // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
|
| // of a string using [] notation. We need to support this too in
|
| // JavaScript.
|
| @@ -2990,7 +3069,6 @@
|
| if (key->IsString()) {
|
| Handle<Object> result;
|
| if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
|
| - ASSERT(attr == NONE);
|
| result = SetElement(js_object, index, value);
|
| } else {
|
| Handle<String> key_string = Handle<String>::cast(key);
|
| @@ -3008,7 +3086,6 @@
|
| Handle<String> name = Handle<String>::cast(converted);
|
|
|
| if (name->AsArrayIndex(&index)) {
|
| - ASSERT(attr == NONE);
|
| return js_object->SetElement(index, *value);
|
| } else {
|
| return js_object->SetProperty(*name, *value, attr);
|
| @@ -3025,8 +3102,6 @@
|
| // Check if the given key is an array index.
|
| uint32_t index;
|
| if (Array::IndexFromObject(*key, &index)) {
|
| - ASSERT(attr == NONE);
|
| -
|
| // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
|
| // of a string using [] notation. We need to support this too in
|
| // JavaScript.
|
| @@ -3043,7 +3118,6 @@
|
|
|
| if (key->IsString()) {
|
| if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
|
| - ASSERT(attr == NONE);
|
| return js_object->SetElement(index, *value);
|
| } else {
|
| Handle<String> key_string = Handle<String>::cast(key);
|
| @@ -3061,7 +3135,6 @@
|
| Handle<String> name = Handle<String>::cast(converted);
|
|
|
| if (name->AsArrayIndex(&index)) {
|
| - ASSERT(attr == NONE);
|
| return js_object->SetElement(index, *value);
|
| } else {
|
| return js_object->IgnoreAttributesAndSetLocalProperty(*name, *value, attr);
|
| @@ -3520,17 +3593,23 @@
|
|
|
|
|
| static Object* Runtime_ToFastProperties(Arguments args) {
|
| + HandleScope scope;
|
| +
|
| ASSERT(args.length() == 1);
|
| Handle<Object> object = args.at<Object>(0);
|
| if (object->IsJSObject()) {
|
| Handle<JSObject> js_object = Handle<JSObject>::cast(object);
|
| - js_object->TransformToFastProperties(0);
|
| + if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
|
| + js_object->TransformToFastProperties(0);
|
| + }
|
| }
|
| return *object;
|
| }
|
|
|
|
|
| static Object* Runtime_ToSlowProperties(Arguments args) {
|
| + HandleScope scope;
|
| +
|
| ASSERT(args.length() == 1);
|
| Handle<Object> object = args.at<Object>(0);
|
| if (object->IsJSObject()) {
|
| @@ -4559,6 +4638,7 @@
|
| static Object* Runtime_Math_abs(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 1);
|
| + Counters::math_abs.Increment();
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| return Heap::AllocateHeapNumber(fabs(x));
|
| @@ -4568,6 +4648,7 @@
|
| static Object* Runtime_Math_acos(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 1);
|
| + Counters::math_acos.Increment();
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
|
| @@ -4577,6 +4658,7 @@
|
| static Object* Runtime_Math_asin(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 1);
|
| + Counters::math_asin.Increment();
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
|
| @@ -4586,6 +4668,7 @@
|
| static Object* Runtime_Math_atan(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 1);
|
| + Counters::math_atan.Increment();
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
|
| @@ -4595,6 +4678,7 @@
|
| static Object* Runtime_Math_atan2(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 2);
|
| + Counters::math_atan2.Increment();
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| CONVERT_DOUBLE_CHECKED(y, args[1]);
|
| @@ -4618,6 +4702,7 @@
|
| static Object* Runtime_Math_ceil(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 1);
|
| + Counters::math_ceil.Increment();
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| return Heap::NumberFromDouble(ceiling(x));
|
| @@ -4627,6 +4712,7 @@
|
| static Object* Runtime_Math_cos(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 1);
|
| + Counters::math_cos.Increment();
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| return TranscendentalCache::Get(TranscendentalCache::COS, x);
|
| @@ -4636,6 +4722,7 @@
|
| static Object* Runtime_Math_exp(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 1);
|
| + Counters::math_exp.Increment();
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| return TranscendentalCache::Get(TranscendentalCache::EXP, x);
|
| @@ -4645,6 +4732,7 @@
|
| static Object* Runtime_Math_floor(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 1);
|
| + Counters::math_floor.Increment();
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| return Heap::NumberFromDouble(floor(x));
|
| @@ -4654,6 +4742,7 @@
|
| static Object* Runtime_Math_log(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 1);
|
| + Counters::math_log.Increment();
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| return TranscendentalCache::Get(TranscendentalCache::LOG, x);
|
| @@ -4694,6 +4783,7 @@
|
| static Object* Runtime_Math_pow(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 2);
|
| + Counters::math_pow.Increment();
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
|
|
| @@ -4732,6 +4822,7 @@
|
| static Object* Runtime_Math_round(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 1);
|
| + Counters::math_round.Increment();
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
|
| @@ -4744,6 +4835,7 @@
|
| static Object* Runtime_Math_sin(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 1);
|
| + Counters::math_sin.Increment();
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| return TranscendentalCache::Get(TranscendentalCache::SIN, x);
|
| @@ -4753,6 +4845,7 @@
|
| static Object* Runtime_Math_sqrt(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 1);
|
| + Counters::math_sqrt.Increment();
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| return Heap::AllocateHeapNumber(sqrt(x));
|
| @@ -4762,47 +4855,13 @@
|
| static Object* Runtime_Math_tan(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 1);
|
| + Counters::math_tan.Increment();
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| return TranscendentalCache::Get(TranscendentalCache::TAN, x);
|
| }
|
|
|
|
|
| -// The NewArguments function is only used when constructing the
|
| -// arguments array when calling non-functions from JavaScript in
|
| -// runtime.js:CALL_NON_FUNCTION.
|
| -static Object* Runtime_NewArguments(Arguments args) {
|
| - NoHandleAllocation ha;
|
| - ASSERT(args.length() == 1);
|
| -
|
| - // ECMA-262, 3rd., 10.1.8, p.39
|
| - CONVERT_CHECKED(JSFunction, callee, args[0]);
|
| -
|
| - // Compute the frame holding the arguments.
|
| - JavaScriptFrameIterator it;
|
| - it.AdvanceToArgumentsFrame();
|
| - JavaScriptFrame* frame = it.frame();
|
| -
|
| - const int length = frame->GetProvidedParametersCount();
|
| - Object* result = Heap::AllocateArgumentsObject(callee, length);
|
| - if (result->IsFailure()) return result;
|
| - if (length > 0) {
|
| - Object* obj = Heap::AllocateFixedArray(length);
|
| - if (obj->IsFailure()) return obj;
|
| - FixedArray* array = FixedArray::cast(obj);
|
| - ASSERT(array->length() == length);
|
| -
|
| - AssertNoAllocation no_gc;
|
| - WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
|
| - for (int i = 0; i < length; i++) {
|
| - array->set(i, frame->GetParameter(i), mode);
|
| - }
|
| - JSObject::cast(result)->set_elements(array);
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -
|
| static Object* Runtime_NewArgumentsFast(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 3);
|
| @@ -4849,21 +4908,21 @@
|
| }
|
|
|
|
|
| -static Code* ComputeConstructStub(Handle<SharedFunctionInfo> shared) {
|
| - // TODO(385): Change this to create a construct stub specialized for
|
| - // the given map to make allocation of simple objects - and maybe
|
| - // arrays - much faster.
|
| - if (FLAG_inline_new
|
| - && shared->has_only_simple_this_property_assignments()) {
|
| +static Code* ComputeConstructStub(Handle<JSFunction> function) {
|
| + Handle<Object> prototype = Factory::null_value();
|
| + if (function->has_instance_prototype()) {
|
| + prototype = Handle<Object>(function->instance_prototype());
|
| + }
|
| + if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
|
| ConstructStubCompiler compiler;
|
| - Object* code = compiler.CompileConstructStub(*shared);
|
| + Object* code = compiler.CompileConstructStub(function->shared());
|
| if (code->IsFailure()) {
|
| return Builtins::builtin(Builtins::JSConstructStubGeneric);
|
| }
|
| return Code::cast(code);
|
| }
|
|
|
| - return shared->construct_stub();
|
| + return function->shared()->construct_stub();
|
| }
|
|
|
|
|
| @@ -4913,10 +4972,9 @@
|
| bool first_allocation = !function->has_initial_map();
|
| Handle<JSObject> result = Factory::NewJSObject(function);
|
| if (first_allocation) {
|
| - Handle<Map> map = Handle<Map>(function->initial_map());
|
| Handle<Code> stub = Handle<Code>(
|
| - ComputeConstructStub(Handle<SharedFunctionInfo>(function->shared())));
|
| - function->shared()->set_construct_stub(*stub);
|
| + ComputeConstructStub(Handle<JSFunction>(function)));
|
| + shared->set_construct_stub(*stub);
|
| }
|
|
|
| Counters::constructed_objects.Increment();
|
| @@ -4955,28 +5013,6 @@
|
| }
|
|
|
|
|
| -static Object* Runtime_GetCalledFunction(Arguments args) {
|
| - HandleScope scope;
|
| - ASSERT(args.length() == 0);
|
| - StackFrameIterator it;
|
| - // Get past the JS-to-C exit frame.
|
| - ASSERT(it.frame()->is_exit());
|
| - it.Advance();
|
| - // Get past the CALL_NON_FUNCTION activation frame.
|
| - ASSERT(it.frame()->is_java_script());
|
| - it.Advance();
|
| - // Argument adaptor frames do not copy the function; we have to skip
|
| - // past them to get to the real calling frame.
|
| - if (it.frame()->is_arguments_adaptor()) it.Advance();
|
| - // Get the function from the top of the expression stack of the
|
| - // calling frame.
|
| - StandardFrame* frame = StandardFrame::cast(it.frame());
|
| - int index = frame->ComputeExpressionsCount() - 1;
|
| - Object* result = frame->GetExpression(index);
|
| - return result;
|
| -}
|
| -
|
| -
|
| static Object* Runtime_GetFunctionDelegate(Arguments args) {
|
| HandleScope scope;
|
| ASSERT(args.length() == 1);
|
| @@ -7981,20 +8017,22 @@
|
|
|
| static Object* Runtime_ProfilerResume(Arguments args) {
|
| NoHandleAllocation ha;
|
| - ASSERT(args.length() == 1);
|
| + ASSERT(args.length() == 2);
|
|
|
| CONVERT_CHECKED(Smi, smi_modules, args[0]);
|
| - v8::V8::ResumeProfilerEx(smi_modules->value());
|
| + CONVERT_CHECKED(Smi, smi_tag, args[1]);
|
| + v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
|
| return Heap::undefined_value();
|
| }
|
|
|
|
|
| static Object* Runtime_ProfilerPause(Arguments args) {
|
| NoHandleAllocation ha;
|
| - ASSERT(args.length() == 1);
|
| + ASSERT(args.length() == 2);
|
|
|
| CONVERT_CHECKED(Smi, smi_modules, args[0]);
|
| - v8::V8::PauseProfilerEx(smi_modules->value());
|
| + CONVERT_CHECKED(Smi, smi_tag, args[1]);
|
| + v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
|
| return Heap::undefined_value();
|
| }
|
|
|
|
|