| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1 | // Copyright 2011 the V8 project authors. All rights reserved. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2 | // Redistribution and use in source and binary forms, with or without | 
 | 3 | // modification, are permitted provided that the following conditions are | 
 | 4 | // met: | 
 | 5 | // | 
 | 6 | //     * Redistributions of source code must retain the above copyright | 
 | 7 | //       notice, this list of conditions and the following disclaimer. | 
 | 8 | //     * Redistributions in binary form must reproduce the above | 
 | 9 | //       copyright notice, this list of conditions and the following | 
 | 10 | //       disclaimer in the documentation and/or other materials provided | 
 | 11 | //       with the distribution. | 
 | 12 | //     * Neither the name of Google Inc. nor the names of its | 
 | 13 | //       contributors may be used to endorse or promote products derived | 
 | 14 | //       from this software without specific prior written permission. | 
 | 15 | // | 
 | 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
 | 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
 | 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
 | 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
 | 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
 | 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
 | 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
 | 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
 | 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 | 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 | 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
 | 27 |  | 
 | 28 | #include <stdlib.h> | 
 | 29 |  | 
 | 30 | #include "v8.h" | 
 | 31 |  | 
 | 32 | #include "accessors.h" | 
 | 33 | #include "api.h" | 
 | 34 | #include "arguments.h" | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 35 | #include "codegen.h" | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 36 | #include "compilation-cache.h" | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 37 | #include "compiler.h" | 
 | 38 | #include "cpu.h" | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 39 | #include "dateparser-inl.h" | 
 | 40 | #include "debug.h" | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 41 | #include "deoptimizer.h" | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 42 | #include "execution.h" | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 43 | #include "global-handles.h" | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 44 | #include "jsregexp.h" | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 45 | #include "liveedit.h" | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 46 | #include "liveobjectlist-inl.h" | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 47 | #include "parser.h" | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 48 | #include "platform.h" | 
 | 49 | #include "runtime.h" | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 50 | #include "runtime-profiler.h" | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 51 | #include "scopeinfo.h" | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 52 | #include "smart-pointer.h" | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 53 | #include "stub-cache.h" | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 54 | #include "v8threads.h" | 
| Steve Block | 5915150 | 2010-09-22 15:07:15 +0100 | [diff] [blame] | 55 | #include "string-search.h" | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 56 |  | 
 | 57 | namespace v8 { | 
 | 58 | namespace internal { | 
 | 59 |  | 
 | 60 |  | 
 | 61 | #define RUNTIME_ASSERT(value) \ | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 62 |   if (!(value)) return isolate->ThrowIllegalOperation(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 63 |  | 
 | 64 | // Cast the given object to a value of the specified type and store | 
 | 65 | // it in a variable with the given name.  If the object is not of the | 
 | 66 | // expected type call IllegalOperation and return. | 
 | 67 | #define CONVERT_CHECKED(Type, name, obj)                             \ | 
 | 68 |   RUNTIME_ASSERT(obj->Is##Type());                                   \ | 
 | 69 |   Type* name = Type::cast(obj); | 
 | 70 |  | 
 | 71 | #define CONVERT_ARG_CHECKED(Type, name, index)                       \ | 
 | 72 |   RUNTIME_ASSERT(args[index]->Is##Type());                           \ | 
 | 73 |   Handle<Type> name = args.at<Type>(index); | 
 | 74 |  | 
 | 75 | // Cast the given object to a boolean and store it in a variable with | 
 | 76 | // the given name.  If the object is not a boolean call IllegalOperation | 
 | 77 | // and return. | 
 | 78 | #define CONVERT_BOOLEAN_CHECKED(name, obj)                            \ | 
 | 79 |   RUNTIME_ASSERT(obj->IsBoolean());                                   \ | 
 | 80 |   bool name = (obj)->IsTrue(); | 
 | 81 |  | 
 | 82 | // Cast the given object to a Smi and store its value in an int variable | 
 | 83 | // with the given name.  If the object is not a Smi call IllegalOperation | 
 | 84 | // and return. | 
 | 85 | #define CONVERT_SMI_CHECKED(name, obj)                            \ | 
 | 86 |   RUNTIME_ASSERT(obj->IsSmi());                                   \ | 
 | 87 |   int name = Smi::cast(obj)->value(); | 
 | 88 |  | 
 | 89 | // Cast the given object to a double and store it in a variable with | 
 | 90 | // the given name.  If the object is not a number (as opposed to | 
 | 91 | // the number not-a-number) call IllegalOperation and return. | 
 | 92 | #define CONVERT_DOUBLE_CHECKED(name, obj)                            \ | 
 | 93 |   RUNTIME_ASSERT(obj->IsNumber());                                   \ | 
 | 94 |   double name = (obj)->Number(); | 
 | 95 |  | 
 | 96 | // Call the specified converter on the object *comand store the result in | 
 | 97 | // a variable of the specified type with the given name.  If the | 
 | 98 | // object is not a Number call IllegalOperation and return. | 
 | 99 | #define CONVERT_NUMBER_CHECKED(type, name, Type, obj)                \ | 
 | 100 |   RUNTIME_ASSERT(obj->IsNumber());                                   \ | 
 | 101 |   type name = NumberTo##Type(obj); | 
 | 102 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 103 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 104 | MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate, | 
 | 105 |                                                    JSObject* boilerplate) { | 
 | 106 |   StackLimitCheck check(isolate); | 
 | 107 |   if (check.HasOverflowed()) return isolate->StackOverflow(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 108 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 109 |   Heap* heap = isolate->heap(); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 110 |   Object* result; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 111 |   { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 112 |     if (!maybe_result->ToObject(&result)) return maybe_result; | 
 | 113 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 114 |   JSObject* copy = JSObject::cast(result); | 
 | 115 |  | 
 | 116 |   // Deep copy local properties. | 
 | 117 |   if (copy->HasFastProperties()) { | 
 | 118 |     FixedArray* properties = copy->properties(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 119 |     for (int i = 0; i < properties->length(); i++) { | 
 | 120 |       Object* value = properties->get(i); | 
 | 121 |       if (value->IsJSObject()) { | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 122 |         JSObject* js_object = JSObject::cast(value); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 123 |         { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 124 |           if (!maybe_result->ToObject(&result)) return maybe_result; | 
 | 125 |         } | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 126 |         properties->set(i, result); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 127 |       } | 
 | 128 |     } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 129 |     int nof = copy->map()->inobject_properties(); | 
 | 130 |     for (int i = 0; i < nof; i++) { | 
 | 131 |       Object* value = copy->InObjectPropertyAt(i); | 
 | 132 |       if (value->IsJSObject()) { | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 133 |         JSObject* js_object = JSObject::cast(value); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 134 |         { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 135 |           if (!maybe_result->ToObject(&result)) return maybe_result; | 
 | 136 |         } | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 137 |         copy->InObjectPropertyAtPut(i, result); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 138 |       } | 
 | 139 |     } | 
 | 140 |   } else { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 141 |     { MaybeObject* maybe_result = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 142 |           heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE)); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 143 |       if (!maybe_result->ToObject(&result)) return maybe_result; | 
 | 144 |     } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 145 |     FixedArray* names = FixedArray::cast(result); | 
 | 146 |     copy->GetLocalPropertyNames(names, 0); | 
 | 147 |     for (int i = 0; i < names->length(); i++) { | 
 | 148 |       ASSERT(names->get(i)->IsString()); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 149 |       String* key_string = String::cast(names->get(i)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 150 |       PropertyAttributes attributes = | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 151 |           copy->GetLocalPropertyAttribute(key_string); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 152 |       // Only deep copy fields from the object literal expression. | 
 | 153 |       // In particular, don't try to copy the length attribute of | 
 | 154 |       // an array. | 
 | 155 |       if (attributes != NONE) continue; | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 156 |       Object* value = | 
 | 157 |           copy->GetProperty(key_string, &attributes)->ToObjectUnchecked(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 158 |       if (value->IsJSObject()) { | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 159 |         JSObject* js_object = JSObject::cast(value); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 160 |         { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 161 |           if (!maybe_result->ToObject(&result)) return maybe_result; | 
 | 162 |         } | 
 | 163 |         { MaybeObject* maybe_result = | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 164 |               // Creating object copy for literals. No strict mode needed. | 
 | 165 |               copy->SetProperty(key_string, result, NONE, kNonStrictMode); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 166 |           if (!maybe_result->ToObject(&result)) return maybe_result; | 
 | 167 |         } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 168 |       } | 
 | 169 |     } | 
 | 170 |   } | 
 | 171 |  | 
 | 172 |   // Deep copy local elements. | 
 | 173 |   // Pixel elements cannot be created using an object literal. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 174 |   ASSERT(!copy->HasExternalArrayElements()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 175 |   switch (copy->GetElementsKind()) { | 
 | 176 |     case JSObject::FAST_ELEMENTS: { | 
 | 177 |       FixedArray* elements = FixedArray::cast(copy->elements()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 178 |       if (elements->map() == heap->fixed_cow_array_map()) { | 
 | 179 |         isolate->counters()->cow_arrays_created_runtime()->Increment(); | 
| Iain Merrick | 7568138 | 2010-08-19 15:07:18 +0100 | [diff] [blame] | 180 | #ifdef DEBUG | 
 | 181 |         for (int i = 0; i < elements->length(); i++) { | 
 | 182 |           ASSERT(!elements->get(i)->IsJSObject()); | 
 | 183 |         } | 
 | 184 | #endif | 
 | 185 |       } else { | 
 | 186 |         for (int i = 0; i < elements->length(); i++) { | 
 | 187 |           Object* value = elements->get(i); | 
 | 188 |           if (value->IsJSObject()) { | 
 | 189 |             JSObject* js_object = JSObject::cast(value); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 190 |             { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, | 
 | 191 |                                                               js_object); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 192 |               if (!maybe_result->ToObject(&result)) return maybe_result; | 
 | 193 |             } | 
| Iain Merrick | 7568138 | 2010-08-19 15:07:18 +0100 | [diff] [blame] | 194 |             elements->set(i, result); | 
 | 195 |           } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 196 |         } | 
 | 197 |       } | 
 | 198 |       break; | 
 | 199 |     } | 
 | 200 |     case JSObject::DICTIONARY_ELEMENTS: { | 
 | 201 |       NumberDictionary* element_dictionary = copy->element_dictionary(); | 
 | 202 |       int capacity = element_dictionary->Capacity(); | 
 | 203 |       for (int i = 0; i < capacity; i++) { | 
 | 204 |         Object* k = element_dictionary->KeyAt(i); | 
 | 205 |         if (element_dictionary->IsKey(k)) { | 
 | 206 |           Object* value = element_dictionary->ValueAt(i); | 
 | 207 |           if (value->IsJSObject()) { | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 208 |             JSObject* js_object = JSObject::cast(value); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 209 |             { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, | 
 | 210 |                                                               js_object); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 211 |               if (!maybe_result->ToObject(&result)) return maybe_result; | 
 | 212 |             } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 213 |             element_dictionary->ValueAtPut(i, result); | 
 | 214 |           } | 
 | 215 |         } | 
 | 216 |       } | 
 | 217 |       break; | 
 | 218 |     } | 
 | 219 |     default: | 
 | 220 |       UNREACHABLE(); | 
 | 221 |       break; | 
 | 222 |   } | 
 | 223 |   return copy; | 
 | 224 | } | 
 | 225 |  | 
 | 226 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 227 | RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 228 |   CONVERT_CHECKED(JSObject, boilerplate, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 229 |   return DeepCopyBoilerplate(isolate, boilerplate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 230 | } | 
 | 231 |  | 
 | 232 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 233 | RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 234 |   CONVERT_CHECKED(JSObject, boilerplate, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 235 |   return isolate->heap()->CopyJSObject(boilerplate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 236 | } | 
 | 237 |  | 
 | 238 |  | 
 | 239 | static Handle<Map> ComputeObjectLiteralMap( | 
 | 240 |     Handle<Context> context, | 
 | 241 |     Handle<FixedArray> constant_properties, | 
 | 242 |     bool* is_result_from_cache) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 243 |   Isolate* isolate = context->GetIsolate(); | 
| Kristian Monsen | 50ef84f | 2010-07-29 15:18:00 +0100 | [diff] [blame] | 244 |   int properties_length = constant_properties->length(); | 
 | 245 |   int number_of_properties = properties_length / 2; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 246 |   if (FLAG_canonicalize_object_literal_maps) { | 
| Kristian Monsen | 50ef84f | 2010-07-29 15:18:00 +0100 | [diff] [blame] | 247 |     // Check that there are only symbols and array indices among keys. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 248 |     int number_of_symbol_keys = 0; | 
| Kristian Monsen | 50ef84f | 2010-07-29 15:18:00 +0100 | [diff] [blame] | 249 |     for (int p = 0; p != properties_length; p += 2) { | 
 | 250 |       Object* key = constant_properties->get(p); | 
 | 251 |       uint32_t element_index = 0; | 
 | 252 |       if (key->IsSymbol()) { | 
 | 253 |         number_of_symbol_keys++; | 
 | 254 |       } else if (key->ToArrayIndex(&element_index)) { | 
 | 255 |         // An index key does not require space in the property backing store. | 
 | 256 |         number_of_properties--; | 
 | 257 |       } else { | 
 | 258 |         // Bail out as a non-symbol non-index key makes caching impossible. | 
 | 259 |         // ASSERT to make sure that the if condition after the loop is false. | 
 | 260 |         ASSERT(number_of_symbol_keys != number_of_properties); | 
 | 261 |         break; | 
 | 262 |       } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 263 |     } | 
| Kristian Monsen | 50ef84f | 2010-07-29 15:18:00 +0100 | [diff] [blame] | 264 |     // If we only have symbols and array indices among keys then we can | 
 | 265 |     // use the map cache in the global context. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 266 |     const int kMaxKeys = 10; | 
 | 267 |     if ((number_of_symbol_keys == number_of_properties) && | 
 | 268 |         (number_of_symbol_keys < kMaxKeys)) { | 
 | 269 |       // Create the fixed array with the key. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 270 |       Handle<FixedArray> keys = | 
 | 271 |           isolate->factory()->NewFixedArray(number_of_symbol_keys); | 
| Kristian Monsen | 50ef84f | 2010-07-29 15:18:00 +0100 | [diff] [blame] | 272 |       if (number_of_symbol_keys > 0) { | 
 | 273 |         int index = 0; | 
 | 274 |         for (int p = 0; p < properties_length; p += 2) { | 
 | 275 |           Object* key = constant_properties->get(p); | 
 | 276 |           if (key->IsSymbol()) { | 
 | 277 |             keys->set(index++, key); | 
 | 278 |           } | 
 | 279 |         } | 
 | 280 |         ASSERT(index == number_of_symbol_keys); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 281 |       } | 
 | 282 |       *is_result_from_cache = true; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 283 |       return isolate->factory()->ObjectLiteralMapFromCache(context, keys); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 284 |     } | 
 | 285 |   } | 
 | 286 |   *is_result_from_cache = false; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 287 |   return isolate->factory()->CopyMap( | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 288 |       Handle<Map>(context->object_function()->initial_map()), | 
 | 289 |       number_of_properties); | 
 | 290 | } | 
 | 291 |  | 
 | 292 |  | 
 | 293 | static Handle<Object> CreateLiteralBoilerplate( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 294 |     Isolate* isolate, | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 295 |     Handle<FixedArray> literals, | 
 | 296 |     Handle<FixedArray> constant_properties); | 
 | 297 |  | 
 | 298 |  | 
 | 299 | static Handle<Object> CreateObjectLiteralBoilerplate( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 300 |     Isolate* isolate, | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 301 |     Handle<FixedArray> literals, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 302 |     Handle<FixedArray> constant_properties, | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 303 |     bool should_have_fast_elements, | 
 | 304 |     bool has_function_literal) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 305 |   // Get the global context from the literals array.  This is the | 
 | 306 |   // context in which the function was created and we use the object | 
 | 307 |   // function from this context to create the object literal.  We do | 
 | 308 |   // not use the object function from the current global context | 
 | 309 |   // because this might be the object function from another context | 
 | 310 |   // which we should not have access to. | 
 | 311 |   Handle<Context> context = | 
 | 312 |       Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals)); | 
 | 313 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 314 |   // In case we have function literals, we want the object to be in | 
 | 315 |   // slow properties mode for now. We don't go in the map cache because | 
 | 316 |   // maps with constant functions can't be shared if the functions are | 
 | 317 |   // not the same (which is the common case). | 
 | 318 |   bool is_result_from_cache = false; | 
 | 319 |   Handle<Map> map = has_function_literal | 
 | 320 |       ? Handle<Map>(context->object_function()->initial_map()) | 
 | 321 |       : ComputeObjectLiteralMap(context, | 
 | 322 |                                 constant_properties, | 
 | 323 |                                 &is_result_from_cache); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 324 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 325 |   Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 326 |  | 
 | 327 |   // Normalize the elements of the boilerplate to save space if needed. | 
 | 328 |   if (!should_have_fast_elements) NormalizeElements(boilerplate); | 
 | 329 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 330 |   // Add the constant properties to the boilerplate. | 
 | 331 |   int length = constant_properties->length(); | 
 | 332 |   bool should_transform = | 
 | 333 |       !is_result_from_cache && boilerplate->HasFastProperties(); | 
 | 334 |   if (should_transform || has_function_literal) { | 
 | 335 |     // Normalize the properties of object to avoid n^2 behavior | 
 | 336 |     // when extending the object multiple properties. Indicate the number of | 
 | 337 |     // properties to be added. | 
 | 338 |     NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2); | 
 | 339 |   } | 
 | 340 |  | 
 | 341 |   for (int index = 0; index < length; index +=2) { | 
 | 342 |     Handle<Object> key(constant_properties->get(index+0), isolate); | 
 | 343 |     Handle<Object> value(constant_properties->get(index+1), isolate); | 
 | 344 |     if (value->IsFixedArray()) { | 
 | 345 |       // The value contains the constant_properties of a | 
 | 346 |       // simple object or array literal. | 
 | 347 |       Handle<FixedArray> array = Handle<FixedArray>::cast(value); | 
 | 348 |       value = CreateLiteralBoilerplate(isolate, literals, array); | 
 | 349 |       if (value.is_null()) return value; | 
 | 350 |     } | 
 | 351 |     Handle<Object> result; | 
 | 352 |     uint32_t element_index = 0; | 
 | 353 |     if (key->IsSymbol()) { | 
 | 354 |       if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) { | 
 | 355 |         // Array index as string (uint32). | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 356 |         result = SetOwnElement(boilerplate, | 
 | 357 |                                element_index, | 
 | 358 |                                value, | 
 | 359 |                                kNonStrictMode); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 360 |       } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 361 |         Handle<String> name(String::cast(*key)); | 
 | 362 |         ASSERT(!name->AsArrayIndex(&element_index)); | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 363 |         result = SetLocalPropertyIgnoreAttributes(boilerplate, name, | 
 | 364 |                                                   value, NONE); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 365 |       } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 366 |     } else if (key->ToArrayIndex(&element_index)) { | 
 | 367 |       // Array index (uint32). | 
 | 368 |       result = SetOwnElement(boilerplate, | 
 | 369 |                              element_index, | 
 | 370 |                              value, | 
 | 371 |                              kNonStrictMode); | 
 | 372 |     } else { | 
 | 373 |       // Non-uint32 number. | 
 | 374 |       ASSERT(key->IsNumber()); | 
 | 375 |       double num = key->Number(); | 
 | 376 |       char arr[100]; | 
 | 377 |       Vector<char> buffer(arr, ARRAY_SIZE(arr)); | 
 | 378 |       const char* str = DoubleToCString(num, buffer); | 
 | 379 |       Handle<String> name = | 
 | 380 |           isolate->factory()->NewStringFromAscii(CStrVector(str)); | 
 | 381 |       result = SetLocalPropertyIgnoreAttributes(boilerplate, name, | 
 | 382 |                                                 value, NONE); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 383 |     } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 384 |     // If setting the property on the boilerplate throws an | 
 | 385 |     // exception, the exception is converted to an empty handle in | 
 | 386 |     // the handle based operations.  In that case, we need to | 
 | 387 |     // convert back to an exception. | 
 | 388 |     if (result.is_null()) return result; | 
 | 389 |   } | 
 | 390 |  | 
 | 391 |   // Transform to fast properties if necessary. For object literals with | 
 | 392 |   // containing function literals we defer this operation until after all | 
 | 393 |   // computed properties have been assigned so that we can generate | 
 | 394 |   // constant function properties. | 
 | 395 |   if (should_transform && !has_function_literal) { | 
 | 396 |     TransformToFastProperties(boilerplate, | 
 | 397 |                               boilerplate->map()->unused_property_fields()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 398 |   } | 
 | 399 |  | 
 | 400 |   return boilerplate; | 
 | 401 | } | 
 | 402 |  | 
 | 403 |  | 
 | 404 | static Handle<Object> CreateArrayLiteralBoilerplate( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 405 |     Isolate* isolate, | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 406 |     Handle<FixedArray> literals, | 
 | 407 |     Handle<FixedArray> elements) { | 
 | 408 |   // Create the JSArray. | 
 | 409 |   Handle<JSFunction> constructor( | 
 | 410 |       JSFunction::GlobalContextFromLiterals(*literals)->array_function()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 411 |   Handle<Object> object = isolate->factory()->NewJSObject(constructor); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 412 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 413 |   const bool is_cow = | 
 | 414 |       (elements->map() == isolate->heap()->fixed_cow_array_map()); | 
| Iain Merrick | 7568138 | 2010-08-19 15:07:18 +0100 | [diff] [blame] | 415 |   Handle<FixedArray> copied_elements = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 416 |       is_cow ? elements : isolate->factory()->CopyFixedArray(elements); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 417 |  | 
 | 418 |   Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements); | 
| Iain Merrick | 7568138 | 2010-08-19 15:07:18 +0100 | [diff] [blame] | 419 |   if (is_cow) { | 
 | 420 | #ifdef DEBUG | 
 | 421 |     // Copy-on-write arrays must be shallow (and simple). | 
 | 422 |     for (int i = 0; i < content->length(); i++) { | 
 | 423 |       ASSERT(!content->get(i)->IsFixedArray()); | 
 | 424 |     } | 
 | 425 | #endif | 
 | 426 |   } else { | 
 | 427 |     for (int i = 0; i < content->length(); i++) { | 
 | 428 |       if (content->get(i)->IsFixedArray()) { | 
 | 429 |         // The value contains the constant_properties of a | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 430 |         // simple object or array literal. | 
| Iain Merrick | 7568138 | 2010-08-19 15:07:18 +0100 | [diff] [blame] | 431 |         Handle<FixedArray> fa(FixedArray::cast(content->get(i))); | 
 | 432 |         Handle<Object> result = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 433 |             CreateLiteralBoilerplate(isolate, literals, fa); | 
| Iain Merrick | 7568138 | 2010-08-19 15:07:18 +0100 | [diff] [blame] | 434 |         if (result.is_null()) return result; | 
 | 435 |         content->set(i, *result); | 
 | 436 |       } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 437 |     } | 
 | 438 |   } | 
 | 439 |  | 
 | 440 |   // Set the elements. | 
 | 441 |   Handle<JSArray>::cast(object)->SetContent(*content); | 
 | 442 |   return object; | 
 | 443 | } | 
 | 444 |  | 
 | 445 |  | 
 | 446 | static Handle<Object> CreateLiteralBoilerplate( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 447 |     Isolate* isolate, | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 448 |     Handle<FixedArray> literals, | 
 | 449 |     Handle<FixedArray> array) { | 
 | 450 |   Handle<FixedArray> elements = CompileTimeValue::GetElements(array); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 451 |   const bool kHasNoFunctionLiteral = false; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 452 |   switch (CompileTimeValue::GetType(array)) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 453 |     case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS: | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 454 |       return CreateObjectLiteralBoilerplate(isolate, | 
 | 455 |                                             literals, | 
 | 456 |                                             elements, | 
 | 457 |                                             true, | 
 | 458 |                                             kHasNoFunctionLiteral); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 459 |     case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS: | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 460 |       return CreateObjectLiteralBoilerplate(isolate, | 
 | 461 |                                             literals, | 
 | 462 |                                             elements, | 
 | 463 |                                             false, | 
 | 464 |                                             kHasNoFunctionLiteral); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 465 |     case CompileTimeValue::ARRAY_LITERAL: | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 466 |       return CreateArrayLiteralBoilerplate(isolate, literals, elements); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 467 |     default: | 
 | 468 |       UNREACHABLE(); | 
 | 469 |       return Handle<Object>::null(); | 
 | 470 |   } | 
 | 471 | } | 
 | 472 |  | 
 | 473 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 474 | RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 475 |   // Takes a FixedArray of elements containing the literal elements of | 
 | 476 |   // the array literal and produces JSArray with those elements. | 
 | 477 |   // Additionally takes the literals array of the surrounding function | 
 | 478 |   // which contains the context from which to get the Array function | 
 | 479 |   // to use for creating the array literal. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 480 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 481 |   ASSERT(args.length() == 3); | 
 | 482 |   CONVERT_ARG_CHECKED(FixedArray, literals, 0); | 
 | 483 |   CONVERT_SMI_CHECKED(literals_index, args[1]); | 
 | 484 |   CONVERT_ARG_CHECKED(FixedArray, elements, 2); | 
 | 485 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 486 |   Handle<Object> object = | 
 | 487 |       CreateArrayLiteralBoilerplate(isolate, literals, elements); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 488 |   if (object.is_null()) return Failure::Exception(); | 
 | 489 |  | 
 | 490 |   // Update the functions literal and return the boilerplate. | 
 | 491 |   literals->set(literals_index, *object); | 
 | 492 |   return *object; | 
 | 493 | } | 
 | 494 |  | 
 | 495 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 496 | RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 497 |   HandleScope scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 498 |   ASSERT(args.length() == 4); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 499 |   CONVERT_ARG_CHECKED(FixedArray, literals, 0); | 
 | 500 |   CONVERT_SMI_CHECKED(literals_index, args[1]); | 
 | 501 |   CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 502 |   CONVERT_SMI_CHECKED(flags, args[3]); | 
 | 503 |   bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; | 
 | 504 |   bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0; | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 505 |  | 
 | 506 |   // Check if boilerplate exists. If not, create it first. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 507 |   Handle<Object> boilerplate(literals->get(literals_index), isolate); | 
 | 508 |   if (*boilerplate == isolate->heap()->undefined_value()) { | 
 | 509 |     boilerplate = CreateObjectLiteralBoilerplate(isolate, | 
 | 510 |                                                  literals, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 511 |                                                  constant_properties, | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 512 |                                                  should_have_fast_elements, | 
 | 513 |                                                  has_function_literal); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 514 |     if (boilerplate.is_null()) return Failure::Exception(); | 
 | 515 |     // Update the functions literal and return the boilerplate. | 
 | 516 |     literals->set(literals_index, *boilerplate); | 
 | 517 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 518 |   return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate)); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 519 | } | 
 | 520 |  | 
 | 521 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 522 | RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 523 |   HandleScope scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 524 |   ASSERT(args.length() == 4); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 525 |   CONVERT_ARG_CHECKED(FixedArray, literals, 0); | 
 | 526 |   CONVERT_SMI_CHECKED(literals_index, args[1]); | 
 | 527 |   CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 528 |   CONVERT_SMI_CHECKED(flags, args[3]); | 
 | 529 |   bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; | 
 | 530 |   bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0; | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 531 |  | 
 | 532 |   // Check if boilerplate exists. If not, create it first. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 533 |   Handle<Object> boilerplate(literals->get(literals_index), isolate); | 
 | 534 |   if (*boilerplate == isolate->heap()->undefined_value()) { | 
 | 535 |     boilerplate = CreateObjectLiteralBoilerplate(isolate, | 
 | 536 |                                                  literals, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 537 |                                                  constant_properties, | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 538 |                                                  should_have_fast_elements, | 
 | 539 |                                                  has_function_literal); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 540 |     if (boilerplate.is_null()) return Failure::Exception(); | 
 | 541 |     // Update the functions literal and return the boilerplate. | 
 | 542 |     literals->set(literals_index, *boilerplate); | 
 | 543 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 544 |   return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate)); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 545 | } | 
 | 546 |  | 
 | 547 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 548 | RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 549 |   HandleScope scope(isolate); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 550 |   ASSERT(args.length() == 3); | 
 | 551 |   CONVERT_ARG_CHECKED(FixedArray, literals, 0); | 
 | 552 |   CONVERT_SMI_CHECKED(literals_index, args[1]); | 
 | 553 |   CONVERT_ARG_CHECKED(FixedArray, elements, 2); | 
 | 554 |  | 
 | 555 |   // Check if boilerplate exists. If not, create it first. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 556 |   Handle<Object> boilerplate(literals->get(literals_index), isolate); | 
 | 557 |   if (*boilerplate == isolate->heap()->undefined_value()) { | 
 | 558 |     boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 559 |     if (boilerplate.is_null()) return Failure::Exception(); | 
 | 560 |     // Update the functions literal and return the boilerplate. | 
 | 561 |     literals->set(literals_index, *boilerplate); | 
 | 562 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 563 |   return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate)); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 564 | } | 
 | 565 |  | 
 | 566 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 567 | RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 568 |   HandleScope scope(isolate); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 569 |   ASSERT(args.length() == 3); | 
 | 570 |   CONVERT_ARG_CHECKED(FixedArray, literals, 0); | 
 | 571 |   CONVERT_SMI_CHECKED(literals_index, args[1]); | 
 | 572 |   CONVERT_ARG_CHECKED(FixedArray, elements, 2); | 
 | 573 |  | 
 | 574 |   // Check if boilerplate exists. If not, create it first. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 575 |   Handle<Object> boilerplate(literals->get(literals_index), isolate); | 
 | 576 |   if (*boilerplate == isolate->heap()->undefined_value()) { | 
 | 577 |     boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 578 |     if (boilerplate.is_null()) return Failure::Exception(); | 
 | 579 |     // Update the functions literal and return the boilerplate. | 
 | 580 |     literals->set(literals_index, *boilerplate); | 
 | 581 |   } | 
| Iain Merrick | 7568138 | 2010-08-19 15:07:18 +0100 | [diff] [blame] | 582 |   if (JSObject::cast(*boilerplate)->elements()->map() == | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 583 |       isolate->heap()->fixed_cow_array_map()) { | 
 | 584 |     isolate->counters()->cow_arrays_created_runtime()->Increment(); | 
| Iain Merrick | 7568138 | 2010-08-19 15:07:18 +0100 | [diff] [blame] | 585 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 586 |   return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate)); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 587 | } | 
 | 588 |  | 
 | 589 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 590 | RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 591 |   ASSERT(args.length() == 2); | 
 | 592 |   CONVERT_CHECKED(String, key, args[0]); | 
 | 593 |   Object* value = args[1]; | 
 | 594 |   // Create a catch context extension object. | 
 | 595 |   JSFunction* constructor = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 596 |       isolate->context()->global_context()-> | 
 | 597 |           context_extension_function(); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 598 |   Object* object; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 599 |   { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 600 |     if (!maybe_object->ToObject(&object)) return maybe_object; | 
 | 601 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 602 |   // Assign the exception value to the catch variable and make sure | 
 | 603 |   // that the catch variable is DontDelete. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 604 |   { MaybeObject* maybe_value = | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 605 |         // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4. | 
 | 606 |         JSObject::cast(object)->SetProperty( | 
 | 607 |             key, value, DONT_DELETE, kNonStrictMode); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 608 |     if (!maybe_value->ToObject(&value)) return maybe_value; | 
 | 609 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 610 |   return object; | 
 | 611 | } | 
 | 612 |  | 
 | 613 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 614 | RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 615 |   NoHandleAllocation ha; | 
 | 616 |   ASSERT(args.length() == 1); | 
 | 617 |   Object* obj = args[0]; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 618 |   if (!obj->IsJSObject()) return isolate->heap()->null_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 619 |   return JSObject::cast(obj)->class_name(); | 
 | 620 | } | 
 | 621 |  | 
 | 622 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 623 | RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 624 |   NoHandleAllocation ha; | 
 | 625 |   ASSERT(args.length() == 2); | 
 | 626 |   // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8). | 
 | 627 |   Object* O = args[0]; | 
 | 628 |   Object* V = args[1]; | 
 | 629 |   while (true) { | 
 | 630 |     Object* prototype = V->GetPrototype(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 631 |     if (prototype->IsNull()) return isolate->heap()->false_value(); | 
 | 632 |     if (O == prototype) return isolate->heap()->true_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 633 |     V = prototype; | 
 | 634 |   } | 
 | 635 | } | 
 | 636 |  | 
 | 637 |  | 
 | 638 | // Inserts an object as the hidden prototype of another object. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 639 | RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 640 |   NoHandleAllocation ha; | 
 | 641 |   ASSERT(args.length() == 2); | 
 | 642 |   CONVERT_CHECKED(JSObject, jsobject, args[0]); | 
 | 643 |   CONVERT_CHECKED(JSObject, proto, args[1]); | 
 | 644 |  | 
 | 645 |   // Sanity checks.  The old prototype (that we are replacing) could | 
 | 646 |   // theoretically be null, but if it is not null then check that we | 
 | 647 |   // didn't already install a hidden prototype here. | 
 | 648 |   RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() || | 
 | 649 |     !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype()); | 
 | 650 |   RUNTIME_ASSERT(!proto->map()->is_hidden_prototype()); | 
 | 651 |  | 
 | 652 |   // Allocate up front before we start altering state in case we get a GC. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 653 |   Object* map_or_failure; | 
 | 654 |   { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions(); | 
 | 655 |     if (!maybe_map_or_failure->ToObject(&map_or_failure)) { | 
 | 656 |       return maybe_map_or_failure; | 
 | 657 |     } | 
 | 658 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 659 |   Map* new_proto_map = Map::cast(map_or_failure); | 
 | 660 |  | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 661 |   { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions(); | 
 | 662 |     if (!maybe_map_or_failure->ToObject(&map_or_failure)) { | 
 | 663 |       return maybe_map_or_failure; | 
 | 664 |     } | 
 | 665 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 666 |   Map* new_map = Map::cast(map_or_failure); | 
 | 667 |  | 
 | 668 |   // Set proto's prototype to be the old prototype of the object. | 
 | 669 |   new_proto_map->set_prototype(jsobject->GetPrototype()); | 
 | 670 |   proto->set_map(new_proto_map); | 
 | 671 |   new_proto_map->set_is_hidden_prototype(); | 
 | 672 |  | 
 | 673 |   // Set the object's prototype to proto. | 
 | 674 |   new_map->set_prototype(proto); | 
 | 675 |   jsobject->set_map(new_map); | 
 | 676 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 677 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 678 | } | 
 | 679 |  | 
 | 680 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 681 | RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 682 |   NoHandleAllocation ha; | 
 | 683 |   ASSERT(args.length() == 0); | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 684 |   JavaScriptFrameIterator it(isolate); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 685 |   return isolate->heap()->ToBoolean(it.frame()->IsConstructor()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 686 | } | 
 | 687 |  | 
 | 688 |  | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 689 | // Recursively traverses hidden prototypes if property is not found | 
 | 690 | static void GetOwnPropertyImplementation(JSObject* obj, | 
 | 691 |                                          String* name, | 
 | 692 |                                          LookupResult* result) { | 
 | 693 |   obj->LocalLookupRealNamedProperty(name, result); | 
 | 694 |  | 
 | 695 |   if (!result->IsProperty()) { | 
 | 696 |     Object* proto = obj->GetPrototype(); | 
 | 697 |     if (proto->IsJSObject() && | 
 | 698 |       JSObject::cast(proto)->map()->is_hidden_prototype()) | 
 | 699 |       GetOwnPropertyImplementation(JSObject::cast(proto), | 
 | 700 |                                    name, result); | 
 | 701 |   } | 
 | 702 | } | 
 | 703 |  | 
 | 704 |  | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 705 | static bool CheckAccessException(LookupResult* result, | 
 | 706 |                                  v8::AccessType access_type) { | 
 | 707 |   if (result->type() == CALLBACKS) { | 
 | 708 |     Object* callback = result->GetCallbackObject(); | 
 | 709 |     if (callback->IsAccessorInfo()) { | 
 | 710 |       AccessorInfo* info = AccessorInfo::cast(callback); | 
 | 711 |       bool can_access = | 
 | 712 |           (access_type == v8::ACCESS_HAS && | 
 | 713 |               (info->all_can_read() || info->all_can_write())) || | 
 | 714 |           (access_type == v8::ACCESS_GET && info->all_can_read()) || | 
 | 715 |           (access_type == v8::ACCESS_SET && info->all_can_write()); | 
 | 716 |       return can_access; | 
 | 717 |     } | 
 | 718 |   } | 
 | 719 |  | 
 | 720 |   return false; | 
 | 721 | } | 
 | 722 |  | 
 | 723 |  | 
 | 724 | static bool CheckAccess(JSObject* obj, | 
 | 725 |                         String* name, | 
 | 726 |                         LookupResult* result, | 
 | 727 |                         v8::AccessType access_type) { | 
 | 728 |   ASSERT(result->IsProperty()); | 
 | 729 |  | 
 | 730 |   JSObject* holder = result->holder(); | 
 | 731 |   JSObject* current = obj; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 732 |   Isolate* isolate = obj->GetIsolate(); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 733 |   while (true) { | 
 | 734 |     if (current->IsAccessCheckNeeded() && | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 735 |         !isolate->MayNamedAccess(current, name, access_type)) { | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 736 |       // Access check callback denied the access, but some properties | 
 | 737 |       // can have a special permissions which override callbacks descision | 
 | 738 |       // (currently see v8::AccessControl). | 
 | 739 |       break; | 
 | 740 |     } | 
 | 741 |  | 
 | 742 |     if (current == holder) { | 
 | 743 |       return true; | 
 | 744 |     } | 
 | 745 |  | 
 | 746 |     current = JSObject::cast(current->GetPrototype()); | 
 | 747 |   } | 
 | 748 |  | 
 | 749 |   // API callbacks can have per callback access exceptions. | 
 | 750 |   switch (result->type()) { | 
 | 751 |     case CALLBACKS: { | 
 | 752 |       if (CheckAccessException(result, access_type)) { | 
 | 753 |         return true; | 
 | 754 |       } | 
 | 755 |       break; | 
 | 756 |     } | 
 | 757 |     case INTERCEPTOR: { | 
 | 758 |       // If the object has an interceptor, try real named properties. | 
 | 759 |       // Overwrite the result to fetch the correct property later. | 
 | 760 |       holder->LookupRealNamedProperty(name, result); | 
 | 761 |       if (result->IsProperty()) { | 
 | 762 |         if (CheckAccessException(result, access_type)) { | 
 | 763 |           return true; | 
 | 764 |         } | 
 | 765 |       } | 
 | 766 |       break; | 
 | 767 |     } | 
 | 768 |     default: | 
 | 769 |       break; | 
 | 770 |   } | 
 | 771 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 772 |   isolate->ReportFailedAccessCheck(current, access_type); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 773 |   return false; | 
 | 774 | } | 
 | 775 |  | 
 | 776 |  | 
 | 777 | // TODO(1095): we should traverse hidden prototype hierachy as well. | 
 | 778 | static bool CheckElementAccess(JSObject* obj, | 
 | 779 |                                uint32_t index, | 
 | 780 |                                v8::AccessType access_type) { | 
 | 781 |   if (obj->IsAccessCheckNeeded() && | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 782 |       !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) { | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 783 |     return false; | 
 | 784 |   } | 
 | 785 |  | 
 | 786 |   return true; | 
 | 787 | } | 
 | 788 |  | 
 | 789 |  | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 790 | // Enumerator used as indices into the array returned from GetOwnProperty | 
 | 791 | enum PropertyDescriptorIndices { | 
 | 792 |   IS_ACCESSOR_INDEX, | 
 | 793 |   VALUE_INDEX, | 
 | 794 |   GETTER_INDEX, | 
 | 795 |   SETTER_INDEX, | 
 | 796 |   WRITABLE_INDEX, | 
 | 797 |   ENUMERABLE_INDEX, | 
 | 798 |   CONFIGURABLE_INDEX, | 
 | 799 |   DESCRIPTOR_SIZE | 
 | 800 | }; | 
 | 801 |  | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 802 | // Returns an array with the property description: | 
 | 803 | //  if args[1] is not a property on args[0] | 
 | 804 | //          returns undefined | 
 | 805 | //  if args[1] is a data property on args[0] | 
 | 806 | //         [false, value, Writeable, Enumerable, Configurable] | 
 | 807 | //  if args[1] is an accessor on args[0] | 
 | 808 | //         [true, GetFunction, SetFunction, Enumerable, Configurable] | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 809 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) { | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 810 |   ASSERT(args.length() == 2); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 811 |   Heap* heap = isolate->heap(); | 
 | 812 |   HandleScope scope(isolate); | 
 | 813 |   Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE); | 
 | 814 |   Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 815 |   LookupResult result; | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 816 |   CONVERT_ARG_CHECKED(JSObject, obj, 0); | 
 | 817 |   CONVERT_ARG_CHECKED(String, name, 1); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 818 |  | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 819 |   // This could be an element. | 
 | 820 |   uint32_t index; | 
 | 821 |   if (name->AsArrayIndex(&index)) { | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 822 |     switch (obj->HasLocalElement(index)) { | 
 | 823 |       case JSObject::UNDEFINED_ELEMENT: | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 824 |         return heap->undefined_value(); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 825 |  | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 826 |       case JSObject::STRING_CHARACTER_ELEMENT: { | 
 | 827 |         // Special handling of string objects according to ECMAScript 5 | 
 | 828 |         // 15.5.5.2. Note that this might be a string object with elements | 
 | 829 |         // other than the actual string value. This is covered by the | 
 | 830 |         // subsequent cases. | 
 | 831 |         Handle<JSValue> js_value = Handle<JSValue>::cast(obj); | 
 | 832 |         Handle<String> str(String::cast(js_value->value())); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 833 |         Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 834 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 835 |         elms->set(IS_ACCESSOR_INDEX, heap->false_value()); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 836 |         elms->set(VALUE_INDEX, *substr); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 837 |         elms->set(WRITABLE_INDEX, heap->false_value()); | 
 | 838 |         elms->set(ENUMERABLE_INDEX,  heap->false_value()); | 
 | 839 |         elms->set(CONFIGURABLE_INDEX, heap->false_value()); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 840 |         return *desc; | 
 | 841 |       } | 
 | 842 |  | 
 | 843 |       case JSObject::INTERCEPTED_ELEMENT: | 
 | 844 |       case JSObject::FAST_ELEMENT: { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 845 |         elms->set(IS_ACCESSOR_INDEX, heap->false_value()); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 846 |         Handle<Object> value = GetElement(obj, index); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 847 |         RETURN_IF_EMPTY_HANDLE(isolate, value); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 848 |         elms->set(VALUE_INDEX, *value); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 849 |         elms->set(WRITABLE_INDEX, heap->true_value()); | 
 | 850 |         elms->set(ENUMERABLE_INDEX,  heap->true_value()); | 
 | 851 |         elms->set(CONFIGURABLE_INDEX, heap->true_value()); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 852 |         return *desc; | 
 | 853 |       } | 
 | 854 |  | 
 | 855 |       case JSObject::DICTIONARY_ELEMENT: { | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 856 |         Handle<JSObject> holder = obj; | 
 | 857 |         if (obj->IsJSGlobalProxy()) { | 
 | 858 |           Object* proto = obj->GetPrototype(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 859 |           if (proto->IsNull()) return heap->undefined_value(); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 860 |           ASSERT(proto->IsJSGlobalObject()); | 
 | 861 |           holder = Handle<JSObject>(JSObject::cast(proto)); | 
 | 862 |         } | 
 | 863 |         NumberDictionary* dictionary = holder->element_dictionary(); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 864 |         int entry = dictionary->FindEntry(index); | 
 | 865 |         ASSERT(entry != NumberDictionary::kNotFound); | 
 | 866 |         PropertyDetails details = dictionary->DetailsAt(entry); | 
 | 867 |         switch (details.type()) { | 
 | 868 |           case CALLBACKS: { | 
 | 869 |             // This is an accessor property with getter and/or setter. | 
 | 870 |             FixedArray* callbacks = | 
 | 871 |                 FixedArray::cast(dictionary->ValueAt(entry)); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 872 |             elms->set(IS_ACCESSOR_INDEX, heap->true_value()); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 873 |             if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) { | 
 | 874 |               elms->set(GETTER_INDEX, callbacks->get(0)); | 
 | 875 |             } | 
 | 876 |             if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) { | 
 | 877 |               elms->set(SETTER_INDEX, callbacks->get(1)); | 
 | 878 |             } | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 879 |             break; | 
 | 880 |           } | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 881 |           case NORMAL: { | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 882 |             // This is a data property. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 883 |             elms->set(IS_ACCESSOR_INDEX, heap->false_value()); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 884 |             Handle<Object> value = GetElement(obj, index); | 
 | 885 |             ASSERT(!value.is_null()); | 
 | 886 |             elms->set(VALUE_INDEX, *value); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 887 |             elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly())); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 888 |             break; | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 889 |           } | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 890 |           default: | 
 | 891 |             UNREACHABLE(); | 
 | 892 |             break; | 
 | 893 |         } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 894 |         elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum())); | 
 | 895 |         elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete())); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 896 |         return *desc; | 
 | 897 |       } | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 898 |     } | 
 | 899 |   } | 
 | 900 |  | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 901 |   // Use recursive implementation to also traverse hidden prototypes | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 902 |   GetOwnPropertyImplementation(*obj, *name, &result); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 903 |  | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 904 |   if (!result.IsProperty()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 905 |     return heap->undefined_value(); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 906 |   } | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 907 |  | 
 | 908 |   if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 909 |     return heap->false_value(); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 910 |   } | 
 | 911 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 912 |   elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum())); | 
 | 913 |   elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete())); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 914 |  | 
 | 915 |   bool is_js_accessor = (result.type() == CALLBACKS) && | 
 | 916 |                         (result.GetCallbackObject()->IsFixedArray()); | 
 | 917 |  | 
 | 918 |   if (is_js_accessor) { | 
 | 919 |     // __defineGetter__/__defineSetter__ callback. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 920 |     elms->set(IS_ACCESSOR_INDEX, heap->true_value()); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 921 |  | 
 | 922 |     FixedArray* structure = FixedArray::cast(result.GetCallbackObject()); | 
 | 923 |     if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) { | 
 | 924 |       elms->set(GETTER_INDEX, structure->get(0)); | 
 | 925 |     } | 
 | 926 |     if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) { | 
 | 927 |       elms->set(SETTER_INDEX, structure->get(1)); | 
 | 928 |     } | 
 | 929 |   } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 930 |     elms->set(IS_ACCESSOR_INDEX, heap->false_value()); | 
 | 931 |     elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly())); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 932 |  | 
 | 933 |     PropertyAttributes attrs; | 
 | 934 |     Object* value; | 
 | 935 |     // GetProperty will check access and report any violations. | 
 | 936 |     { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs); | 
 | 937 |       if (!maybe_value->ToObject(&value)) return maybe_value; | 
 | 938 |     } | 
 | 939 |     elms->set(VALUE_INDEX, value); | 
 | 940 |   } | 
 | 941 |  | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 942 |   return *desc; | 
 | 943 | } | 
 | 944 |  | 
 | 945 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 946 | RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) { | 
| Steve Block | 8defd9f | 2010-07-08 12:39:36 +0100 | [diff] [blame] | 947 |   ASSERT(args.length() == 1); | 
 | 948 |   CONVERT_CHECKED(JSObject, obj, args[0]); | 
 | 949 |   return obj->PreventExtensions(); | 
 | 950 | } | 
 | 951 |  | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 952 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 953 | RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) { | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 954 |   ASSERT(args.length() == 1); | 
 | 955 |   CONVERT_CHECKED(JSObject, obj, args[0]); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 956 |   if (obj->IsJSGlobalProxy()) { | 
 | 957 |     Object* proto = obj->GetPrototype(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 958 |     if (proto->IsNull()) return isolate->heap()->false_value(); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 959 |     ASSERT(proto->IsJSGlobalObject()); | 
 | 960 |     obj = JSObject::cast(proto); | 
 | 961 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 962 |   return obj->map()->is_extensible() ? isolate->heap()->true_value() | 
 | 963 |                                      : isolate->heap()->false_value(); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 964 | } | 
 | 965 |  | 
 | 966 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 967 | RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 968 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 969 |   ASSERT(args.length() == 3); | 
 | 970 |   CONVERT_ARG_CHECKED(JSRegExp, re, 0); | 
 | 971 |   CONVERT_ARG_CHECKED(String, pattern, 1); | 
 | 972 |   CONVERT_ARG_CHECKED(String, flags, 2); | 
 | 973 |   Handle<Object> result = RegExpImpl::Compile(re, pattern, flags); | 
 | 974 |   if (result.is_null()) return Failure::Exception(); | 
 | 975 |   return *result; | 
 | 976 | } | 
 | 977 |  | 
 | 978 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 979 | RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 980 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 981 |   ASSERT(args.length() == 1); | 
 | 982 |   CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 983 |   return *isolate->factory()->CreateApiFunction(data); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 984 | } | 
 | 985 |  | 
 | 986 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 987 | RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 988 |   ASSERT(args.length() == 1); | 
 | 989 |   Object* arg = args[0]; | 
 | 990 |   bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 991 |   return isolate->heap()->ToBoolean(result); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 992 | } | 
 | 993 |  | 
 | 994 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 995 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 996 |   ASSERT(args.length() == 2); | 
 | 997 |   CONVERT_CHECKED(HeapObject, templ, args[0]); | 
 | 998 |   CONVERT_CHECKED(Smi, field, args[1]); | 
 | 999 |   int index = field->value(); | 
 | 1000 |   int offset = index * kPointerSize + HeapObject::kHeaderSize; | 
 | 1001 |   InstanceType type = templ->map()->instance_type(); | 
 | 1002 |   RUNTIME_ASSERT(type ==  FUNCTION_TEMPLATE_INFO_TYPE || | 
 | 1003 |                  type ==  OBJECT_TEMPLATE_INFO_TYPE); | 
 | 1004 |   RUNTIME_ASSERT(offset > 0); | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 1005 |   if (type == FUNCTION_TEMPLATE_INFO_TYPE) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1006 |     RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize); | 
 | 1007 |   } else { | 
 | 1008 |     RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize); | 
 | 1009 |   } | 
 | 1010 |   return *HeapObject::RawField(templ, offset); | 
 | 1011 | } | 
 | 1012 |  | 
 | 1013 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1014 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1015 |   ASSERT(args.length() == 1); | 
 | 1016 |   CONVERT_CHECKED(HeapObject, object, args[0]); | 
 | 1017 |   Map* old_map = object->map(); | 
 | 1018 |   bool needs_access_checks = old_map->is_access_check_needed(); | 
 | 1019 |   if (needs_access_checks) { | 
 | 1020 |     // Copy map so it won't interfere constructor's initial map. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 1021 |     Object* new_map; | 
 | 1022 |     { MaybeObject* maybe_new_map = old_map->CopyDropTransitions(); | 
 | 1023 |       if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; | 
 | 1024 |     } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1025 |  | 
 | 1026 |     Map::cast(new_map)->set_is_access_check_needed(false); | 
 | 1027 |     object->set_map(Map::cast(new_map)); | 
 | 1028 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1029 |   return needs_access_checks ? isolate->heap()->true_value() | 
 | 1030 |                              : isolate->heap()->false_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1031 | } | 
 | 1032 |  | 
 | 1033 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1034 | RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1035 |   ASSERT(args.length() == 1); | 
 | 1036 |   CONVERT_CHECKED(HeapObject, object, args[0]); | 
 | 1037 |   Map* old_map = object->map(); | 
 | 1038 |   if (!old_map->is_access_check_needed()) { | 
 | 1039 |     // Copy map so it won't interfere constructor's initial map. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 1040 |     Object* new_map; | 
 | 1041 |     { MaybeObject* maybe_new_map = old_map->CopyDropTransitions(); | 
 | 1042 |       if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; | 
 | 1043 |     } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1044 |  | 
 | 1045 |     Map::cast(new_map)->set_is_access_check_needed(true); | 
 | 1046 |     object->set_map(Map::cast(new_map)); | 
 | 1047 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1048 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1049 | } | 
 | 1050 |  | 
 | 1051 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1052 | static Failure* ThrowRedeclarationError(Isolate* isolate, | 
 | 1053 |                                         const char* type, | 
 | 1054 |                                         Handle<String> name) { | 
 | 1055 |   HandleScope scope(isolate); | 
 | 1056 |   Handle<Object> type_handle = | 
 | 1057 |       isolate->factory()->NewStringFromAscii(CStrVector(type)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1058 |   Handle<Object> args[2] = { type_handle, name }; | 
 | 1059 |   Handle<Object> error = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1060 |       isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2)); | 
 | 1061 |   return isolate->Throw(*error); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1062 | } | 
 | 1063 |  | 
 | 1064 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1065 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1066 |   ASSERT(args.length() == 4); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1067 |   HandleScope scope(isolate); | 
 | 1068 |   Handle<GlobalObject> global = Handle<GlobalObject>( | 
 | 1069 |       isolate->context()->global()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1070 |  | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 1071 |   Handle<Context> context = args.at<Context>(0); | 
 | 1072 |   CONVERT_ARG_CHECKED(FixedArray, pairs, 1); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1073 |   bool is_eval = Smi::cast(args[2])->value() == 1; | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1074 |   StrictModeFlag strict_mode = | 
 | 1075 |       static_cast<StrictModeFlag>(Smi::cast(args[3])->value()); | 
 | 1076 |   ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1077 |  | 
 | 1078 |   // Compute the property attributes. According to ECMA-262, section | 
 | 1079 |   // 13, page 71, the property must be read-only and | 
 | 1080 |   // non-deletable. However, neither SpiderMonkey nor KJS creates the | 
 | 1081 |   // property as read-only, so we don't either. | 
 | 1082 |   PropertyAttributes base = is_eval ? NONE : DONT_DELETE; | 
 | 1083 |  | 
 | 1084 |   // Traverse the name/value pairs and set the properties. | 
 | 1085 |   int length = pairs->length(); | 
 | 1086 |   for (int i = 0; i < length; i += 2) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1087 |     HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1088 |     Handle<String> name(String::cast(pairs->get(i))); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1089 |     Handle<Object> value(pairs->get(i + 1), isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1090 |  | 
 | 1091 |     // We have to declare a global const property. To capture we only | 
 | 1092 |     // assign to it when evaluating the assignment for "const x = | 
 | 1093 |     // <expr>" the initial value is the hole. | 
 | 1094 |     bool is_const_property = value->IsTheHole(); | 
 | 1095 |  | 
 | 1096 |     if (value->IsUndefined() || is_const_property) { | 
 | 1097 |       // Lookup the property in the global object, and don't set the | 
 | 1098 |       // value of the variable if the property is already there. | 
 | 1099 |       LookupResult lookup; | 
 | 1100 |       global->Lookup(*name, &lookup); | 
 | 1101 |       if (lookup.IsProperty()) { | 
 | 1102 |         // Determine if the property is local by comparing the holder | 
 | 1103 |         // against the global object. The information will be used to | 
 | 1104 |         // avoid throwing re-declaration errors when declaring | 
 | 1105 |         // variables or constants that exist in the prototype chain. | 
 | 1106 |         bool is_local = (*global == lookup.holder()); | 
 | 1107 |         // Get the property attributes and determine if the property is | 
 | 1108 |         // read-only. | 
 | 1109 |         PropertyAttributes attributes = global->GetPropertyAttribute(*name); | 
 | 1110 |         bool is_read_only = (attributes & READ_ONLY) != 0; | 
 | 1111 |         if (lookup.type() == INTERCEPTOR) { | 
 | 1112 |           // If the interceptor says the property is there, we | 
 | 1113 |           // just return undefined without overwriting the property. | 
 | 1114 |           // Otherwise, we continue to setting the property. | 
 | 1115 |           if (attributes != ABSENT) { | 
 | 1116 |             // Check if the existing property conflicts with regards to const. | 
 | 1117 |             if (is_local && (is_read_only || is_const_property)) { | 
 | 1118 |               const char* type = (is_read_only) ? "const" : "var"; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1119 |               return ThrowRedeclarationError(isolate, type, name); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1120 |             }; | 
 | 1121 |             // The property already exists without conflicting: Go to | 
 | 1122 |             // the next declaration. | 
 | 1123 |             continue; | 
 | 1124 |           } | 
 | 1125 |           // Fall-through and introduce the absent property by using | 
 | 1126 |           // SetProperty. | 
 | 1127 |         } else { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1128 |           // For const properties, we treat a callback with this name | 
 | 1129 |           // even in the prototype as a conflicting declaration. | 
 | 1130 |           if (is_const_property && (lookup.type() == CALLBACKS)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1131 |             return ThrowRedeclarationError(isolate, "const", name); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1132 |           } | 
 | 1133 |           // Otherwise, we check for locally conflicting declarations. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1134 |           if (is_local && (is_read_only || is_const_property)) { | 
 | 1135 |             const char* type = (is_read_only) ? "const" : "var"; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1136 |             return ThrowRedeclarationError(isolate, type, name); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1137 |           } | 
 | 1138 |           // The property already exists without conflicting: Go to | 
 | 1139 |           // the next declaration. | 
 | 1140 |           continue; | 
 | 1141 |         } | 
 | 1142 |       } | 
 | 1143 |     } else { | 
 | 1144 |       // Copy the function and update its context. Use it as value. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1145 |       Handle<SharedFunctionInfo> shared = | 
 | 1146 |           Handle<SharedFunctionInfo>::cast(value); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1147 |       Handle<JSFunction> function = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1148 |           isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, | 
 | 1149 |                                                                 context, | 
 | 1150 |                                                                 TENURED); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1151 |       value = function; | 
 | 1152 |     } | 
 | 1153 |  | 
 | 1154 |     LookupResult lookup; | 
 | 1155 |     global->LocalLookup(*name, &lookup); | 
 | 1156 |  | 
 | 1157 |     PropertyAttributes attributes = is_const_property | 
 | 1158 |         ? static_cast<PropertyAttributes>(base | READ_ONLY) | 
 | 1159 |         : base; | 
 | 1160 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1161 |     // There's a local property that we need to overwrite because | 
 | 1162 |     // we're either declaring a function or there's an interceptor | 
 | 1163 |     // that claims the property is absent. | 
 | 1164 |     // | 
 | 1165 |     // Check for conflicting re-declarations. We cannot have | 
 | 1166 |     // conflicting types in case of intercepted properties because | 
 | 1167 |     // they are absent. | 
 | 1168 |     if (lookup.IsProperty() && | 
 | 1169 |         (lookup.type() != INTERCEPTOR) && | 
 | 1170 |         (lookup.IsReadOnly() || is_const_property)) { | 
 | 1171 |       const char* type = (lookup.IsReadOnly()) ? "const" : "var"; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1172 |       return ThrowRedeclarationError(isolate, type, name); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1173 |     } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1174 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1175 |     // Safari does not allow the invocation of callback setters for | 
 | 1176 |     // function declarations. To mimic this behavior, we do not allow | 
 | 1177 |     // the invocation of setters for function values. This makes a | 
 | 1178 |     // difference for global functions with the same names as event | 
 | 1179 |     // handlers such as "function onload() {}". Firefox does call the | 
 | 1180 |     // onload setter in those case and Safari does not. We follow | 
 | 1181 |     // Safari for compatibility. | 
 | 1182 |     if (value->IsJSFunction()) { | 
 | 1183 |       // Do not change DONT_DELETE to false from true. | 
 | 1184 |       if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) { | 
 | 1185 |         attributes = static_cast<PropertyAttributes>( | 
 | 1186 |             attributes | (lookup.GetAttributes() & DONT_DELETE)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1187 |       } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1188 |       RETURN_IF_EMPTY_HANDLE(isolate, | 
 | 1189 |                              SetLocalPropertyIgnoreAttributes(global, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1190 |                                                               name, | 
 | 1191 |                                                               value, | 
 | 1192 |                                                               attributes)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1193 |     } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1194 |       RETURN_IF_EMPTY_HANDLE(isolate, | 
 | 1195 |                              SetProperty(global, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1196 |                                          name, | 
 | 1197 |                                          value, | 
 | 1198 |                                          attributes, | 
 | 1199 |                                          strict_mode)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1200 |     } | 
 | 1201 |   } | 
 | 1202 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1203 |   ASSERT(!isolate->has_pending_exception()); | 
 | 1204 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1205 | } | 
 | 1206 |  | 
 | 1207 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1208 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1209 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1210 |   ASSERT(args.length() == 4); | 
 | 1211 |  | 
 | 1212 |   CONVERT_ARG_CHECKED(Context, context, 0); | 
 | 1213 |   Handle<String> name(String::cast(args[1])); | 
 | 1214 |   PropertyAttributes mode = | 
 | 1215 |       static_cast<PropertyAttributes>(Smi::cast(args[2])->value()); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 1216 |   RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1217 |   Handle<Object> initial_value(args[3], isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1218 |  | 
 | 1219 |   // Declarations are always done in the function context. | 
 | 1220 |   context = Handle<Context>(context->fcontext()); | 
 | 1221 |  | 
 | 1222 |   int index; | 
 | 1223 |   PropertyAttributes attributes; | 
 | 1224 |   ContextLookupFlags flags = DONT_FOLLOW_CHAINS; | 
 | 1225 |   Handle<Object> holder = | 
 | 1226 |       context->Lookup(name, flags, &index, &attributes); | 
 | 1227 |  | 
 | 1228 |   if (attributes != ABSENT) { | 
 | 1229 |     // The name was declared before; check for conflicting | 
 | 1230 |     // re-declarations: This is similar to the code in parser.cc in | 
 | 1231 |     // the AstBuildingParser::Declare function. | 
 | 1232 |     if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) { | 
 | 1233 |       // Functions are not read-only. | 
 | 1234 |       ASSERT(mode != READ_ONLY || initial_value->IsTheHole()); | 
 | 1235 |       const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var"; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1236 |       return ThrowRedeclarationError(isolate, type, name); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1237 |     } | 
 | 1238 |  | 
 | 1239 |     // Initialize it if necessary. | 
 | 1240 |     if (*initial_value != NULL) { | 
 | 1241 |       if (index >= 0) { | 
 | 1242 |         // The variable or constant context slot should always be in | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 1243 |         // the function context or the arguments object. | 
 | 1244 |         if (holder->IsContext()) { | 
 | 1245 |           ASSERT(holder.is_identical_to(context)); | 
 | 1246 |           if (((attributes & READ_ONLY) == 0) || | 
 | 1247 |               context->get(index)->IsTheHole()) { | 
 | 1248 |             context->set(index, *initial_value); | 
 | 1249 |           } | 
 | 1250 |         } else { | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 1251 |           // The holder is an arguments object. | 
 | 1252 |           Handle<JSObject> arguments(Handle<JSObject>::cast(holder)); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1253 |           Handle<Object> result = SetElement(arguments, index, initial_value, | 
 | 1254 |                                              kNonStrictMode); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 1255 |           if (result.is_null()) return Failure::Exception(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1256 |         } | 
 | 1257 |       } else { | 
 | 1258 |         // Slow case: The property is not in the FixedArray part of the context. | 
 | 1259 |         Handle<JSObject> context_ext = Handle<JSObject>::cast(holder); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 1260 |         RETURN_IF_EMPTY_HANDLE( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1261 |             isolate, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1262 |             SetProperty(context_ext, name, initial_value, | 
 | 1263 |                         mode, kNonStrictMode)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1264 |       } | 
 | 1265 |     } | 
 | 1266 |  | 
 | 1267 |   } else { | 
 | 1268 |     // The property is not in the function context. It needs to be | 
 | 1269 |     // "declared" in the function context's extension context, or in the | 
 | 1270 |     // global context. | 
 | 1271 |     Handle<JSObject> context_ext; | 
 | 1272 |     if (context->has_extension()) { | 
 | 1273 |       // The function context's extension context exists - use it. | 
 | 1274 |       context_ext = Handle<JSObject>(context->extension()); | 
 | 1275 |     } else { | 
 | 1276 |       // The function context's extension context does not exists - allocate | 
 | 1277 |       // it. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1278 |       context_ext = isolate->factory()->NewJSObject( | 
 | 1279 |           isolate->context_extension_function()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1280 |       // And store it in the extension slot. | 
 | 1281 |       context->set_extension(*context_ext); | 
 | 1282 |     } | 
 | 1283 |     ASSERT(*context_ext != NULL); | 
 | 1284 |  | 
 | 1285 |     // Declare the property by setting it to the initial value if provided, | 
 | 1286 |     // or undefined, and use the correct mode (e.g. READ_ONLY attribute for | 
 | 1287 |     // constant declarations). | 
 | 1288 |     ASSERT(!context_ext->HasLocalProperty(*name)); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1289 |     Handle<Object> value(isolate->heap()->undefined_value(), isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1290 |     if (*initial_value != NULL) value = initial_value; | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1291 |     // Declaring a const context slot is a conflicting declaration if | 
 | 1292 |     // there is a callback with that name in a prototype. It is | 
 | 1293 |     // allowed to introduce const variables in | 
 | 1294 |     // JSContextExtensionObjects. They are treated specially in | 
 | 1295 |     // SetProperty and no setters are invoked for those since they are | 
 | 1296 |     // not real JSObjects. | 
 | 1297 |     if (initial_value->IsTheHole() && | 
 | 1298 |         !context_ext->IsJSContextExtensionObject()) { | 
 | 1299 |       LookupResult lookup; | 
 | 1300 |       context_ext->Lookup(*name, &lookup); | 
 | 1301 |       if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1302 |         return ThrowRedeclarationError(isolate, "const", name); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1303 |       } | 
 | 1304 |     } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1305 |     RETURN_IF_EMPTY_HANDLE(isolate, | 
 | 1306 |                            SetProperty(context_ext, name, value, mode, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1307 |                                        kNonStrictMode)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1308 |   } | 
 | 1309 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1310 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1311 | } | 
 | 1312 |  | 
 | 1313 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1314 | RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1315 |   NoHandleAllocation nha; | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1316 |   // args[0] == name | 
 | 1317 |   // args[1] == strict_mode | 
 | 1318 |   // args[2] == value (optional) | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1319 |  | 
 | 1320 |   // Determine if we need to assign to the variable if it already | 
 | 1321 |   // exists (based on the number of arguments). | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1322 |   RUNTIME_ASSERT(args.length() == 2 || args.length() == 3); | 
 | 1323 |   bool assign = args.length() == 3; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1324 |  | 
 | 1325 |   CONVERT_ARG_CHECKED(String, name, 0); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1326 |   GlobalObject* global = isolate->context()->global(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1327 |   RUNTIME_ASSERT(args[1]->IsSmi()); | 
 | 1328 |   StrictModeFlag strict_mode = | 
 | 1329 |       static_cast<StrictModeFlag>(Smi::cast(args[1])->value()); | 
 | 1330 |   ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1331 |  | 
 | 1332 |   // According to ECMA-262, section 12.2, page 62, the property must | 
 | 1333 |   // not be deletable. | 
 | 1334 |   PropertyAttributes attributes = DONT_DELETE; | 
 | 1335 |  | 
 | 1336 |   // Lookup the property locally in the global object. If it isn't | 
 | 1337 |   // there, there is a property with this name in the prototype chain. | 
 | 1338 |   // We follow Safari and Firefox behavior and only set the property | 
 | 1339 |   // locally if there is an explicit initialization value that we have | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1340 |   // to assign to the property. | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 1341 |   // Note that objects can have hidden prototypes, so we need to traverse | 
 | 1342 |   // the whole chain of hidden prototypes to do a 'local' lookup. | 
 | 1343 |   JSObject* real_holder = global; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1344 |   LookupResult lookup; | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 1345 |   while (true) { | 
 | 1346 |     real_holder->LocalLookup(*name, &lookup); | 
 | 1347 |     if (lookup.IsProperty()) { | 
 | 1348 |       // Determine if this is a redeclaration of something read-only. | 
 | 1349 |       if (lookup.IsReadOnly()) { | 
 | 1350 |         // If we found readonly property on one of hidden prototypes, | 
 | 1351 |         // just shadow it. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1352 |         if (real_holder != isolate->context()->global()) break; | 
 | 1353 |         return ThrowRedeclarationError(isolate, "const", name); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 1354 |       } | 
 | 1355 |  | 
 | 1356 |       // Determine if this is a redeclaration of an intercepted read-only | 
 | 1357 |       // property and figure out if the property exists at all. | 
 | 1358 |       bool found = true; | 
 | 1359 |       PropertyType type = lookup.type(); | 
 | 1360 |       if (type == INTERCEPTOR) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1361 |         HandleScope handle_scope(isolate); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 1362 |         Handle<JSObject> holder(real_holder); | 
 | 1363 |         PropertyAttributes intercepted = holder->GetPropertyAttribute(*name); | 
 | 1364 |         real_holder = *holder; | 
 | 1365 |         if (intercepted == ABSENT) { | 
 | 1366 |           // The interceptor claims the property isn't there. We need to | 
 | 1367 |           // make sure to introduce it. | 
 | 1368 |           found = false; | 
 | 1369 |         } else if ((intercepted & READ_ONLY) != 0) { | 
 | 1370 |           // The property is present, but read-only. Since we're trying to | 
 | 1371 |           // overwrite it with a variable declaration we must throw a | 
 | 1372 |           // re-declaration error.  However if we found readonly property | 
 | 1373 |           // on one of hidden prototypes, just shadow it. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1374 |           if (real_holder != isolate->context()->global()) break; | 
 | 1375 |           return ThrowRedeclarationError(isolate, "const", name); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 1376 |         } | 
 | 1377 |       } | 
 | 1378 |  | 
 | 1379 |       if (found && !assign) { | 
 | 1380 |         // The global property is there and we're not assigning any value | 
 | 1381 |         // to it. Just return. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1382 |         return isolate->heap()->undefined_value(); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 1383 |       } | 
 | 1384 |  | 
 | 1385 |       // Assign the value (or undefined) to the property. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1386 |       Object* value = (assign) ? args[2] : isolate->heap()->undefined_value(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1387 |       return real_holder->SetProperty( | 
 | 1388 |           &lookup, *name, value, attributes, strict_mode); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1389 |     } | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 1390 |  | 
 | 1391 |     Object* proto = real_holder->GetPrototype(); | 
 | 1392 |     if (!proto->IsJSObject()) | 
 | 1393 |       break; | 
 | 1394 |  | 
 | 1395 |     if (!JSObject::cast(proto)->map()->is_hidden_prototype()) | 
 | 1396 |       break; | 
 | 1397 |  | 
 | 1398 |     real_holder = JSObject::cast(proto); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1399 |   } | 
 | 1400 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1401 |   global = isolate->context()->global(); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 1402 |   if (assign) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1403 |     return global->SetProperty(*name, args[2], attributes, strict_mode); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1404 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1405 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1406 | } | 
 | 1407 |  | 
 | 1408 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1409 | RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1410 |   // All constants are declared with an initial value. The name | 
 | 1411 |   // of the constant is the first argument and the initial value | 
 | 1412 |   // is the second. | 
 | 1413 |   RUNTIME_ASSERT(args.length() == 2); | 
 | 1414 |   CONVERT_ARG_CHECKED(String, name, 0); | 
 | 1415 |   Handle<Object> value = args.at<Object>(1); | 
 | 1416 |  | 
 | 1417 |   // Get the current global object from top. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1418 |   GlobalObject* global = isolate->context()->global(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1419 |  | 
 | 1420 |   // According to ECMA-262, section 12.2, page 62, the property must | 
 | 1421 |   // not be deletable. Since it's a const, it must be READ_ONLY too. | 
 | 1422 |   PropertyAttributes attributes = | 
 | 1423 |       static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY); | 
 | 1424 |  | 
 | 1425 |   // Lookup the property locally in the global object. If it isn't | 
 | 1426 |   // there, we add the property and take special precautions to always | 
 | 1427 |   // add it as a local property even in case of callbacks in the | 
 | 1428 |   // prototype chain (this rules out using SetProperty). | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 1429 |   // We use SetLocalPropertyIgnoreAttributes instead | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1430 |   LookupResult lookup; | 
 | 1431 |   global->LocalLookup(*name, &lookup); | 
 | 1432 |   if (!lookup.IsProperty()) { | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 1433 |     return global->SetLocalPropertyIgnoreAttributes(*name, | 
 | 1434 |                                                     *value, | 
 | 1435 |                                                     attributes); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1436 |   } | 
 | 1437 |  | 
 | 1438 |   // Determine if this is a redeclaration of something not | 
 | 1439 |   // read-only. In case the result is hidden behind an interceptor we | 
 | 1440 |   // need to ask it for the property attributes. | 
 | 1441 |   if (!lookup.IsReadOnly()) { | 
 | 1442 |     if (lookup.type() != INTERCEPTOR) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1443 |       return ThrowRedeclarationError(isolate, "var", name); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1444 |     } | 
 | 1445 |  | 
 | 1446 |     PropertyAttributes intercepted = global->GetPropertyAttribute(*name); | 
 | 1447 |  | 
 | 1448 |     // Throw re-declaration error if the intercepted property is present | 
 | 1449 |     // but not read-only. | 
 | 1450 |     if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1451 |       return ThrowRedeclarationError(isolate, "var", name); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1452 |     } | 
 | 1453 |  | 
 | 1454 |     // Restore global object from context (in case of GC) and continue | 
 | 1455 |     // with setting the value because the property is either absent or | 
 | 1456 |     // read-only. We also have to do redo the lookup. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1457 |     HandleScope handle_scope(isolate); | 
 | 1458 |     Handle<GlobalObject> global(isolate->context()->global()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1459 |  | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 1460 |     // BUG 1213575: Handle the case where we have to set a read-only | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1461 |     // property through an interceptor and only do it if it's | 
 | 1462 |     // uninitialized, e.g. the hole. Nirk... | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1463 |     // Passing non-strict mode because the property is writable. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1464 |     RETURN_IF_EMPTY_HANDLE(isolate, | 
 | 1465 |                            SetProperty(global, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1466 |                                        name, | 
 | 1467 |                                        value, | 
 | 1468 |                                        attributes, | 
 | 1469 |                                        kNonStrictMode)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1470 |     return *value; | 
 | 1471 |   } | 
 | 1472 |  | 
 | 1473 |   // Set the value, but only we're assigning the initial value to a | 
 | 1474 |   // constant. For now, we determine this by checking if the | 
 | 1475 |   // current value is the hole. | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1476 |   // Strict mode handling not needed (const disallowed in strict mode). | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1477 |   PropertyType type = lookup.type(); | 
 | 1478 |   if (type == FIELD) { | 
 | 1479 |     FixedArray* properties = global->properties(); | 
 | 1480 |     int index = lookup.GetFieldIndex(); | 
 | 1481 |     if (properties->get(index)->IsTheHole()) { | 
 | 1482 |       properties->set(index, *value); | 
 | 1483 |     } | 
 | 1484 |   } else if (type == NORMAL) { | 
 | 1485 |     if (global->GetNormalizedProperty(&lookup)->IsTheHole()) { | 
 | 1486 |       global->SetNormalizedProperty(&lookup, *value); | 
 | 1487 |     } | 
 | 1488 |   } else { | 
 | 1489 |     // Ignore re-initialization of constants that have already been | 
 | 1490 |     // assigned a function value. | 
 | 1491 |     ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION); | 
 | 1492 |   } | 
 | 1493 |  | 
 | 1494 |   // Use the set value as the result of the operation. | 
 | 1495 |   return *value; | 
 | 1496 | } | 
 | 1497 |  | 
 | 1498 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1499 | RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1500 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1501 |   ASSERT(args.length() == 3); | 
 | 1502 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1503 |   Handle<Object> value(args[0], isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1504 |   ASSERT(!value->IsTheHole()); | 
 | 1505 |   CONVERT_ARG_CHECKED(Context, context, 1); | 
 | 1506 |   Handle<String> name(String::cast(args[2])); | 
 | 1507 |  | 
 | 1508 |   // Initializations are always done in the function context. | 
 | 1509 |   context = Handle<Context>(context->fcontext()); | 
 | 1510 |  | 
 | 1511 |   int index; | 
 | 1512 |   PropertyAttributes attributes; | 
 | 1513 |   ContextLookupFlags flags = FOLLOW_CHAINS; | 
 | 1514 |   Handle<Object> holder = | 
 | 1515 |       context->Lookup(name, flags, &index, &attributes); | 
 | 1516 |  | 
 | 1517 |   // In most situations, the property introduced by the const | 
 | 1518 |   // declaration should be present in the context extension object. | 
 | 1519 |   // However, because declaration and initialization are separate, the | 
 | 1520 |   // property might have been deleted (if it was introduced by eval) | 
 | 1521 |   // before we reach the initialization point. | 
 | 1522 |   // | 
 | 1523 |   // Example: | 
 | 1524 |   // | 
 | 1525 |   //    function f() { eval("delete x; const x;"); } | 
 | 1526 |   // | 
 | 1527 |   // In that case, the initialization behaves like a normal assignment | 
 | 1528 |   // to property 'x'. | 
 | 1529 |   if (index >= 0) { | 
 | 1530 |     // Property was found in a context. | 
 | 1531 |     if (holder->IsContext()) { | 
 | 1532 |       // The holder cannot be the function context.  If it is, there | 
 | 1533 |       // should have been a const redeclaration error when declaring | 
 | 1534 |       // the const property. | 
 | 1535 |       ASSERT(!holder.is_identical_to(context)); | 
 | 1536 |       if ((attributes & READ_ONLY) == 0) { | 
 | 1537 |         Handle<Context>::cast(holder)->set(index, *value); | 
 | 1538 |       } | 
 | 1539 |     } else { | 
 | 1540 |       // The holder is an arguments object. | 
 | 1541 |       ASSERT((attributes & READ_ONLY) == 0); | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 1542 |       Handle<JSObject> arguments(Handle<JSObject>::cast(holder)); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1543 |       RETURN_IF_EMPTY_HANDLE( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1544 |           isolate, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1545 |           SetElement(arguments, index, value, kNonStrictMode)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1546 |     } | 
 | 1547 |     return *value; | 
 | 1548 |   } | 
 | 1549 |  | 
 | 1550 |   // The property could not be found, we introduce it in the global | 
 | 1551 |   // context. | 
 | 1552 |   if (attributes == ABSENT) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1553 |     Handle<JSObject> global = Handle<JSObject>( | 
 | 1554 |         isolate->context()->global()); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1555 |     // Strict mode not needed (const disallowed in strict mode). | 
 | 1556 |     RETURN_IF_EMPTY_HANDLE( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1557 |         isolate, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1558 |         SetProperty(global, name, value, NONE, kNonStrictMode)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1559 |     return *value; | 
 | 1560 |   } | 
 | 1561 |  | 
 | 1562 |   // The property was present in a context extension object. | 
 | 1563 |   Handle<JSObject> context_ext = Handle<JSObject>::cast(holder); | 
 | 1564 |  | 
 | 1565 |   if (*context_ext == context->extension()) { | 
 | 1566 |     // This is the property that was introduced by the const | 
 | 1567 |     // declaration.  Set it if it hasn't been set before.  NOTE: We | 
 | 1568 |     // cannot use GetProperty() to get the current value as it | 
 | 1569 |     // 'unholes' the value. | 
 | 1570 |     LookupResult lookup; | 
 | 1571 |     context_ext->LocalLookupRealNamedProperty(*name, &lookup); | 
 | 1572 |     ASSERT(lookup.IsProperty());  // the property was declared | 
 | 1573 |     ASSERT(lookup.IsReadOnly());  // and it was declared as read-only | 
 | 1574 |  | 
 | 1575 |     PropertyType type = lookup.type(); | 
 | 1576 |     if (type == FIELD) { | 
 | 1577 |       FixedArray* properties = context_ext->properties(); | 
 | 1578 |       int index = lookup.GetFieldIndex(); | 
 | 1579 |       if (properties->get(index)->IsTheHole()) { | 
 | 1580 |         properties->set(index, *value); | 
 | 1581 |       } | 
 | 1582 |     } else if (type == NORMAL) { | 
 | 1583 |       if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) { | 
 | 1584 |         context_ext->SetNormalizedProperty(&lookup, *value); | 
 | 1585 |       } | 
 | 1586 |     } else { | 
 | 1587 |       // We should not reach here. Any real, named property should be | 
 | 1588 |       // either a field or a dictionary slot. | 
 | 1589 |       UNREACHABLE(); | 
 | 1590 |     } | 
 | 1591 |   } else { | 
 | 1592 |     // The property was found in a different context extension object. | 
 | 1593 |     // Set it if it is not a read-only property. | 
 | 1594 |     if ((attributes & READ_ONLY) == 0) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1595 |       // Strict mode not needed (const disallowed in strict mode). | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 1596 |       RETURN_IF_EMPTY_HANDLE( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1597 |           isolate, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1598 |           SetProperty(context_ext, name, value, attributes, kNonStrictMode)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1599 |     } | 
 | 1600 |   } | 
 | 1601 |  | 
 | 1602 |   return *value; | 
 | 1603 | } | 
 | 1604 |  | 
 | 1605 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1606 | RUNTIME_FUNCTION(MaybeObject*, | 
 | 1607 |                  Runtime_OptimizeObjectForAddingMultipleProperties) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1608 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1609 |   ASSERT(args.length() == 2); | 
 | 1610 |   CONVERT_ARG_CHECKED(JSObject, object, 0); | 
 | 1611 |   CONVERT_SMI_CHECKED(properties, args[1]); | 
 | 1612 |   if (object->HasFastProperties()) { | 
 | 1613 |     NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties); | 
 | 1614 |   } | 
 | 1615 |   return *object; | 
 | 1616 | } | 
 | 1617 |  | 
 | 1618 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1619 | RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1620 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1621 |   ASSERT(args.length() == 4); | 
 | 1622 |   CONVERT_ARG_CHECKED(JSRegExp, regexp, 0); | 
 | 1623 |   CONVERT_ARG_CHECKED(String, subject, 1); | 
 | 1624 |   // Due to the way the JS calls are constructed this must be less than the | 
 | 1625 |   // length of a string, i.e. it is always a Smi.  We check anyway for security. | 
 | 1626 |   CONVERT_SMI_CHECKED(index, args[2]); | 
 | 1627 |   CONVERT_ARG_CHECKED(JSArray, last_match_info, 3); | 
 | 1628 |   RUNTIME_ASSERT(last_match_info->HasFastElements()); | 
 | 1629 |   RUNTIME_ASSERT(index >= 0); | 
 | 1630 |   RUNTIME_ASSERT(index <= subject->length()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1631 |   isolate->counters()->regexp_entry_runtime()->Increment(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1632 |   Handle<Object> result = RegExpImpl::Exec(regexp, | 
 | 1633 |                                            subject, | 
 | 1634 |                                            index, | 
 | 1635 |                                            last_match_info); | 
 | 1636 |   if (result.is_null()) return Failure::Exception(); | 
 | 1637 |   return *result; | 
 | 1638 | } | 
 | 1639 |  | 
 | 1640 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1641 | RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1642 |   ASSERT(args.length() == 3); | 
 | 1643 |   CONVERT_SMI_CHECKED(elements_count, args[0]); | 
 | 1644 |   if (elements_count > JSArray::kMaxFastElementsLength) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1645 |     return isolate->ThrowIllegalOperation(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1646 |   } | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 1647 |   Object* new_object; | 
 | 1648 |   { MaybeObject* maybe_new_object = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1649 |         isolate->heap()->AllocateFixedArrayWithHoles(elements_count); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 1650 |     if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object; | 
 | 1651 |   } | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1652 |   FixedArray* elements = FixedArray::cast(new_object); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1653 |   { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw( | 
 | 1654 |       JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 1655 |     if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object; | 
 | 1656 |   } | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1657 |   { | 
 | 1658 |     AssertNoAllocation no_gc; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1659 |     HandleScope scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1660 |     reinterpret_cast<HeapObject*>(new_object)-> | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1661 |         set_map(isolate->global_context()->regexp_result_map()); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1662 |   } | 
 | 1663 |   JSArray* array = JSArray::cast(new_object); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1664 |   array->set_properties(isolate->heap()->empty_fixed_array()); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1665 |   array->set_elements(elements); | 
 | 1666 |   array->set_length(Smi::FromInt(elements_count)); | 
 | 1667 |   // Write in-object properties after the length of the array. | 
 | 1668 |   array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]); | 
 | 1669 |   array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]); | 
 | 1670 |   return array; | 
 | 1671 | } | 
 | 1672 |  | 
 | 1673 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1674 | RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1675 |   AssertNoAllocation no_alloc; | 
 | 1676 |   ASSERT(args.length() == 5); | 
 | 1677 |   CONVERT_CHECKED(JSRegExp, regexp, args[0]); | 
 | 1678 |   CONVERT_CHECKED(String, source, args[1]); | 
 | 1679 |  | 
 | 1680 |   Object* global = args[2]; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1681 |   if (!global->IsTrue()) global = isolate->heap()->false_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1682 |  | 
 | 1683 |   Object* ignoreCase = args[3]; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1684 |   if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1685 |  | 
 | 1686 |   Object* multiline = args[4]; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1687 |   if (!multiline->IsTrue()) multiline = isolate->heap()->false_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1688 |  | 
 | 1689 |   Map* map = regexp->map(); | 
 | 1690 |   Object* constructor = map->constructor(); | 
 | 1691 |   if (constructor->IsJSFunction() && | 
 | 1692 |       JSFunction::cast(constructor)->initial_map() == map) { | 
 | 1693 |     // If we still have the original map, set in-object properties directly. | 
 | 1694 |     regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source); | 
 | 1695 |     // TODO(lrn): Consider skipping write barrier on booleans as well. | 
 | 1696 |     // Both true and false should be in oldspace at all times. | 
 | 1697 |     regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global); | 
 | 1698 |     regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase); | 
 | 1699 |     regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline); | 
 | 1700 |     regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, | 
 | 1701 |                                   Smi::FromInt(0), | 
 | 1702 |                                   SKIP_WRITE_BARRIER); | 
 | 1703 |     return regexp; | 
 | 1704 |   } | 
 | 1705 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1706 |   // Map has changed, so use generic, but slower, method. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1707 |   PropertyAttributes final = | 
 | 1708 |       static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE); | 
 | 1709 |   PropertyAttributes writable = | 
 | 1710 |       static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1711 |   Heap* heap = isolate->heap(); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 1712 |   MaybeObject* result; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1713 |   result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(), | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 1714 |                                                     source, | 
 | 1715 |                                                     final); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 1716 |   ASSERT(!result->IsFailure()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1717 |   result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(), | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 1718 |                                                     global, | 
 | 1719 |                                                     final); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 1720 |   ASSERT(!result->IsFailure()); | 
 | 1721 |   result = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1722 |       regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(), | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 1723 |                                                ignoreCase, | 
 | 1724 |                                                final); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 1725 |   ASSERT(!result->IsFailure()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1726 |   result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(), | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 1727 |                                                     multiline, | 
 | 1728 |                                                     final); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 1729 |   ASSERT(!result->IsFailure()); | 
 | 1730 |   result = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1731 |       regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(), | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 1732 |                                                Smi::FromInt(0), | 
 | 1733 |                                                writable); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 1734 |   ASSERT(!result->IsFailure()); | 
 | 1735 |   USE(result); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1736 |   return regexp; | 
 | 1737 | } | 
 | 1738 |  | 
 | 1739 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1740 | RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1741 |   HandleScope scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1742 |   ASSERT(args.length() == 1); | 
 | 1743 |   CONVERT_ARG_CHECKED(JSArray, prototype, 0); | 
 | 1744 |   // This is necessary to enable fast checks for absence of elements | 
 | 1745 |   // on Array.prototype and below. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1746 |   prototype->set_elements(isolate->heap()->empty_fixed_array()); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1747 |   return Smi::FromInt(0); | 
 | 1748 | } | 
 | 1749 |  | 
 | 1750 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1751 | static Handle<JSFunction> InstallBuiltin(Isolate* isolate, | 
 | 1752 |                                          Handle<JSObject> holder, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1753 |                                          const char* name, | 
| Kristian Monsen | 25f6136 | 2010-05-21 11:50:48 +0100 | [diff] [blame] | 1754 |                                          Builtins::Name builtin_name) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1755 |   Handle<String> key = isolate->factory()->LookupAsciiSymbol(name); | 
 | 1756 |   Handle<Code> code(isolate->builtins()->builtin(builtin_name)); | 
 | 1757 |   Handle<JSFunction> optimized = | 
 | 1758 |       isolate->factory()->NewFunction(key, | 
 | 1759 |                                       JS_OBJECT_TYPE, | 
 | 1760 |                                       JSObject::kHeaderSize, | 
 | 1761 |                                       code, | 
 | 1762 |                                       false); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1763 |   optimized->shared()->DontAdaptArguments(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1764 |   SetProperty(holder, key, optimized, NONE, kStrictMode); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1765 |   return optimized; | 
 | 1766 | } | 
 | 1767 |  | 
 | 1768 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1769 | RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1770 |   HandleScope scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1771 |   ASSERT(args.length() == 1); | 
 | 1772 |   CONVERT_ARG_CHECKED(JSObject, holder, 0); | 
 | 1773 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1774 |   InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop); | 
 | 1775 |   InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush); | 
 | 1776 |   InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift); | 
 | 1777 |   InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift); | 
 | 1778 |   InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice); | 
 | 1779 |   InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice); | 
 | 1780 |   InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1781 |  | 
 | 1782 |   return *holder; | 
 | 1783 | } | 
 | 1784 |  | 
 | 1785 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1786 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1787 |   // Returns a real global receiver, not one of builtins object. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1788 |   Context* global_context = | 
 | 1789 |       isolate->context()->global()->global_context(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1790 |   return global_context->global()->global_receiver(); | 
 | 1791 | } | 
 | 1792 |  | 
 | 1793 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1794 | RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1795 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1796 |   ASSERT(args.length() == 4); | 
 | 1797 |   CONVERT_ARG_CHECKED(FixedArray, literals, 0); | 
 | 1798 |   int index = Smi::cast(args[1])->value(); | 
 | 1799 |   Handle<String> pattern = args.at<String>(2); | 
 | 1800 |   Handle<String> flags = args.at<String>(3); | 
 | 1801 |  | 
 | 1802 |   // Get the RegExp function from the context in the literals array. | 
 | 1803 |   // This is the RegExp function from the context in which the | 
 | 1804 |   // function was created.  We do not use the RegExp function from the | 
 | 1805 |   // current global context because this might be the RegExp function | 
 | 1806 |   // from another context which we should not have access to. | 
 | 1807 |   Handle<JSFunction> constructor = | 
 | 1808 |       Handle<JSFunction>( | 
 | 1809 |           JSFunction::GlobalContextFromLiterals(*literals)->regexp_function()); | 
 | 1810 |   // Compute the regular expression literal. | 
 | 1811 |   bool has_pending_exception; | 
 | 1812 |   Handle<Object> regexp = | 
 | 1813 |       RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags, | 
 | 1814 |                                       &has_pending_exception); | 
 | 1815 |   if (has_pending_exception) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1816 |     ASSERT(isolate->has_pending_exception()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1817 |     return Failure::Exception(); | 
 | 1818 |   } | 
 | 1819 |   literals->set(index, *regexp); | 
 | 1820 |   return *regexp; | 
 | 1821 | } | 
 | 1822 |  | 
 | 1823 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1824 | RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1825 |   NoHandleAllocation ha; | 
 | 1826 |   ASSERT(args.length() == 1); | 
 | 1827 |  | 
 | 1828 |   CONVERT_CHECKED(JSFunction, f, args[0]); | 
 | 1829 |   return f->shared()->name(); | 
 | 1830 | } | 
 | 1831 |  | 
 | 1832 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1833 | RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1834 |   NoHandleAllocation ha; | 
 | 1835 |   ASSERT(args.length() == 2); | 
 | 1836 |  | 
 | 1837 |   CONVERT_CHECKED(JSFunction, f, args[0]); | 
 | 1838 |   CONVERT_CHECKED(String, name, args[1]); | 
 | 1839 |   f->shared()->set_name(name); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1840 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1841 | } | 
 | 1842 |  | 
 | 1843 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1844 | RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1845 |   NoHandleAllocation ha; | 
 | 1846 |   ASSERT(args.length() == 1); | 
 | 1847 |  | 
 | 1848 |   CONVERT_CHECKED(JSFunction, f, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1849 |   Object* obj = f->RemovePrototype(); | 
 | 1850 |   if (obj->IsFailure()) return obj; | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1851 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1852 |   return isolate->heap()->undefined_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1853 | } | 
 | 1854 |  | 
 | 1855 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1856 | RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1857 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1858 |   ASSERT(args.length() == 1); | 
 | 1859 |  | 
 | 1860 |   CONVERT_CHECKED(JSFunction, fun, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1861 |   Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate); | 
 | 1862 |   if (!script->IsScript()) return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1863 |  | 
 | 1864 |   return *GetScriptWrapper(Handle<Script>::cast(script)); | 
 | 1865 | } | 
 | 1866 |  | 
 | 1867 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1868 | RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1869 |   NoHandleAllocation ha; | 
 | 1870 |   ASSERT(args.length() == 1); | 
 | 1871 |  | 
 | 1872 |   CONVERT_CHECKED(JSFunction, f, args[0]); | 
 | 1873 |   return f->shared()->GetSourceCode(); | 
 | 1874 | } | 
 | 1875 |  | 
 | 1876 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1877 | RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1878 |   NoHandleAllocation ha; | 
 | 1879 |   ASSERT(args.length() == 1); | 
 | 1880 |  | 
 | 1881 |   CONVERT_CHECKED(JSFunction, fun, args[0]); | 
 | 1882 |   int pos = fun->shared()->start_position(); | 
 | 1883 |   return Smi::FromInt(pos); | 
 | 1884 | } | 
 | 1885 |  | 
 | 1886 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1887 | RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1888 |   ASSERT(args.length() == 2); | 
 | 1889 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 1890 |   CONVERT_CHECKED(Code, code, args[0]); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1891 |   CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]); | 
 | 1892 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1893 |   RUNTIME_ASSERT(0 <= offset && offset < code->Size()); | 
 | 1894 |  | 
 | 1895 |   Address pc = code->address() + offset; | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 1896 |   return Smi::FromInt(code->SourcePosition(pc)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1897 | } | 
 | 1898 |  | 
 | 1899 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1900 | RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1901 |   NoHandleAllocation ha; | 
 | 1902 |   ASSERT(args.length() == 2); | 
 | 1903 |  | 
 | 1904 |   CONVERT_CHECKED(JSFunction, fun, args[0]); | 
 | 1905 |   CONVERT_CHECKED(String, name, args[1]); | 
 | 1906 |   fun->SetInstanceClassName(name); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1907 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1908 | } | 
 | 1909 |  | 
 | 1910 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1911 | RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1912 |   NoHandleAllocation ha; | 
 | 1913 |   ASSERT(args.length() == 2); | 
 | 1914 |  | 
 | 1915 |   CONVERT_CHECKED(JSFunction, fun, args[0]); | 
 | 1916 |   CONVERT_CHECKED(Smi, length, args[1]); | 
 | 1917 |   fun->shared()->set_length(length->value()); | 
 | 1918 |   return length; | 
 | 1919 | } | 
 | 1920 |  | 
 | 1921 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1922 | RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1923 |   NoHandleAllocation ha; | 
 | 1924 |   ASSERT(args.length() == 2); | 
 | 1925 |  | 
 | 1926 |   CONVERT_CHECKED(JSFunction, fun, args[0]); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1927 |   ASSERT(fun->should_have_prototype()); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 1928 |   Object* obj; | 
 | 1929 |   { MaybeObject* maybe_obj = | 
 | 1930 |         Accessors::FunctionSetPrototype(fun, args[1], NULL); | 
 | 1931 |     if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 
 | 1932 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1933 |   return args[0];  // return TOS | 
 | 1934 | } | 
 | 1935 |  | 
 | 1936 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1937 | RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1938 |   NoHandleAllocation ha; | 
 | 1939 |   ASSERT(args.length() == 1); | 
 | 1940 |  | 
 | 1941 |   CONVERT_CHECKED(JSFunction, f, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1942 |   return f->shared()->IsApiFunction() ? isolate->heap()->true_value() | 
 | 1943 |                                       : isolate->heap()->false_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1944 | } | 
 | 1945 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1946 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1947 | RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1948 |   NoHandleAllocation ha; | 
 | 1949 |   ASSERT(args.length() == 1); | 
 | 1950 |  | 
 | 1951 |   CONVERT_CHECKED(JSFunction, f, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1952 |   return f->IsBuiltin() ? isolate->heap()->true_value() : | 
 | 1953 |                           isolate->heap()->false_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1954 | } | 
 | 1955 |  | 
 | 1956 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 1957 | RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1958 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1959 |   ASSERT(args.length() == 2); | 
 | 1960 |  | 
 | 1961 |   CONVERT_ARG_CHECKED(JSFunction, target, 0); | 
 | 1962 |   Handle<Object> code = args.at<Object>(1); | 
 | 1963 |  | 
 | 1964 |   Handle<Context> context(target->context()); | 
 | 1965 |  | 
 | 1966 |   if (!code->IsNull()) { | 
 | 1967 |     RUNTIME_ASSERT(code->IsJSFunction()); | 
 | 1968 |     Handle<JSFunction> fun = Handle<JSFunction>::cast(code); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 1969 |     Handle<SharedFunctionInfo> shared(fun->shared()); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 1970 |  | 
 | 1971 |     if (!EnsureCompiled(shared, KEEP_EXCEPTION)) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1972 |       return Failure::Exception(); | 
 | 1973 |     } | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 1974 |     // Since we don't store the source for this we should never | 
 | 1975 |     // optimize this. | 
 | 1976 |     shared->code()->set_optimizable(false); | 
 | 1977 |  | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 1978 |     // Set the code, scope info, formal parameter count, | 
 | 1979 |     // and the length of the target function. | 
| Iain Merrick | 7568138 | 2010-08-19 15:07:18 +0100 | [diff] [blame] | 1980 |     target->shared()->set_code(shared->code()); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 1981 |     target->ReplaceCode(shared->code()); | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 1982 |     target->shared()->set_scope_info(shared->scope_info()); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 1983 |     target->shared()->set_length(shared->length()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1984 |     target->shared()->set_formal_parameter_count( | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 1985 |         shared->formal_parameter_count()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1986 |     // Set the source code of the target function to undefined. | 
 | 1987 |     // SetCode is only used for built-in constructors like String, | 
 | 1988 |     // Array, and Object, and some web code | 
 | 1989 |     // doesn't like seeing source code for constructors. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 1990 |     target->shared()->set_script(isolate->heap()->undefined_value()); | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 1991 |     target->shared()->code()->set_optimizable(false); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1992 |     // Clear the optimization hints related to the compiled code as these are no | 
 | 1993 |     // longer valid when the code is overwritten. | 
 | 1994 |     target->shared()->ClearThisPropertyAssignmentsInfo(); | 
 | 1995 |     context = Handle<Context>(fun->context()); | 
 | 1996 |  | 
 | 1997 |     // Make sure we get a fresh copy of the literal vector to avoid | 
 | 1998 |     // cross context contamination. | 
 | 1999 |     int number_of_literals = fun->NumberOfLiterals(); | 
 | 2000 |     Handle<FixedArray> literals = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2001 |         isolate->factory()->NewFixedArray(number_of_literals, TENURED); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2002 |     if (number_of_literals > 0) { | 
 | 2003 |       // Insert the object, regexp and array functions in the literals | 
 | 2004 |       // array prefix.  These are the functions that will be used when | 
 | 2005 |       // creating object, regexp and array literals. | 
 | 2006 |       literals->set(JSFunction::kLiteralGlobalContextIndex, | 
 | 2007 |                     context->global_context()); | 
 | 2008 |     } | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 2009 |     // It's okay to skip the write barrier here because the literals | 
 | 2010 |     // are guaranteed to be in old space. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2011 |     target->set_literals(*literals, SKIP_WRITE_BARRIER); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2012 |     target->set_next_function_link(isolate->heap()->undefined_value()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2013 |   } | 
 | 2014 |  | 
 | 2015 |   target->set_context(*context); | 
 | 2016 |   return *target; | 
 | 2017 | } | 
 | 2018 |  | 
 | 2019 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 2020 | RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2021 |   HandleScope scope(isolate); | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 2022 |   ASSERT(args.length() == 2); | 
 | 2023 |   CONVERT_ARG_CHECKED(JSFunction, function, 0); | 
 | 2024 |   CONVERT_SMI_CHECKED(num, args[1]); | 
 | 2025 |   RUNTIME_ASSERT(num >= 0); | 
 | 2026 |   SetExpectedNofProperties(function, num); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2027 |   return isolate->heap()->undefined_value(); | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 2028 | } | 
 | 2029 |  | 
 | 2030 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2031 | MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate, | 
 | 2032 |                                                  Object* char_code) { | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 2033 |   uint32_t code; | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 2034 |   if (char_code->ToArrayIndex(&code)) { | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 2035 |     if (code <= 0xffff) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2036 |       return isolate->heap()->LookupSingleCharacterStringFromCode(code); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 2037 |     } | 
 | 2038 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2039 |   return isolate->heap()->empty_string(); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 2040 | } | 
 | 2041 |  | 
 | 2042 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 2043 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2044 |   NoHandleAllocation ha; | 
 | 2045 |   ASSERT(args.length() == 2); | 
 | 2046 |  | 
 | 2047 |   CONVERT_CHECKED(String, subject, args[0]); | 
 | 2048 |   Object* index = args[1]; | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 2049 |   RUNTIME_ASSERT(index->IsNumber()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2050 |  | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 2051 |   uint32_t i = 0; | 
 | 2052 |   if (index->IsSmi()) { | 
 | 2053 |     int value = Smi::cast(index)->value(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2054 |     if (value < 0) return isolate->heap()->nan_value(); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 2055 |     i = value; | 
 | 2056 |   } else { | 
 | 2057 |     ASSERT(index->IsHeapNumber()); | 
 | 2058 |     double value = HeapNumber::cast(index)->value(); | 
 | 2059 |     i = static_cast<uint32_t>(DoubleToInteger(value)); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 2060 |   } | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 2061 |  | 
 | 2062 |   // Flatten the string.  If someone wants to get a char at an index | 
 | 2063 |   // in a cons string, it is likely that more indices will be | 
 | 2064 |   // accessed. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 2065 |   Object* flat; | 
 | 2066 |   { MaybeObject* maybe_flat = subject->TryFlatten(); | 
 | 2067 |     if (!maybe_flat->ToObject(&flat)) return maybe_flat; | 
 | 2068 |   } | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 2069 |   subject = String::cast(flat); | 
 | 2070 |  | 
 | 2071 |   if (i >= static_cast<uint32_t>(subject->length())) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2072 |     return isolate->heap()->nan_value(); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 2073 |   } | 
 | 2074 |  | 
 | 2075 |   return Smi::FromInt(subject->Get(i)); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 2076 | } | 
 | 2077 |  | 
 | 2078 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 2079 | RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2080 |   NoHandleAllocation ha; | 
 | 2081 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2082 |   return CharFromCode(isolate, args[0]); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2083 | } | 
 | 2084 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2085 |  | 
 | 2086 | class FixedArrayBuilder { | 
 | 2087 |  public: | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2088 |   explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity) | 
 | 2089 |       : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)), | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2090 |         length_(0) { | 
 | 2091 |     // Require a non-zero initial size. Ensures that doubling the size to | 
 | 2092 |     // extend the array will work. | 
 | 2093 |     ASSERT(initial_capacity > 0); | 
 | 2094 |   } | 
 | 2095 |  | 
 | 2096 |   explicit FixedArrayBuilder(Handle<FixedArray> backing_store) | 
 | 2097 |       : array_(backing_store), | 
 | 2098 |         length_(0) { | 
 | 2099 |     // Require a non-zero initial size. Ensures that doubling the size to | 
 | 2100 |     // extend the array will work. | 
 | 2101 |     ASSERT(backing_store->length() > 0); | 
 | 2102 |   } | 
 | 2103 |  | 
 | 2104 |   bool HasCapacity(int elements) { | 
 | 2105 |     int length = array_->length(); | 
 | 2106 |     int required_length = length_ + elements; | 
 | 2107 |     return (length >= required_length); | 
 | 2108 |   } | 
 | 2109 |  | 
 | 2110 |   void EnsureCapacity(int elements) { | 
 | 2111 |     int length = array_->length(); | 
 | 2112 |     int required_length = length_ + elements; | 
 | 2113 |     if (length < required_length) { | 
 | 2114 |       int new_length = length; | 
 | 2115 |       do { | 
 | 2116 |         new_length *= 2; | 
 | 2117 |       } while (new_length < required_length); | 
 | 2118 |       Handle<FixedArray> extended_array = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2119 |           array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2120 |       array_->CopyTo(0, *extended_array, 0, length_); | 
 | 2121 |       array_ = extended_array; | 
 | 2122 |     } | 
 | 2123 |   } | 
 | 2124 |  | 
 | 2125 |   void Add(Object* value) { | 
 | 2126 |     ASSERT(length_ < capacity()); | 
 | 2127 |     array_->set(length_, value); | 
 | 2128 |     length_++; | 
 | 2129 |   } | 
 | 2130 |  | 
 | 2131 |   void Add(Smi* value) { | 
 | 2132 |     ASSERT(length_ < capacity()); | 
 | 2133 |     array_->set(length_, value); | 
 | 2134 |     length_++; | 
 | 2135 |   } | 
 | 2136 |  | 
 | 2137 |   Handle<FixedArray> array() { | 
 | 2138 |     return array_; | 
 | 2139 |   } | 
 | 2140 |  | 
 | 2141 |   int length() { | 
 | 2142 |     return length_; | 
 | 2143 |   } | 
 | 2144 |  | 
 | 2145 |   int capacity() { | 
 | 2146 |     return array_->length(); | 
 | 2147 |   } | 
 | 2148 |  | 
 | 2149 |   Handle<JSArray> ToJSArray() { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2150 |     Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2151 |     result_array->set_length(Smi::FromInt(length_)); | 
 | 2152 |     return result_array; | 
 | 2153 |   } | 
 | 2154 |  | 
 | 2155 |   Handle<JSArray> ToJSArray(Handle<JSArray> target_array) { | 
 | 2156 |     target_array->set_elements(*array_); | 
 | 2157 |     target_array->set_length(Smi::FromInt(length_)); | 
 | 2158 |     return target_array; | 
 | 2159 |   } | 
 | 2160 |  | 
 | 2161 |  private: | 
 | 2162 |   Handle<FixedArray> array_; | 
 | 2163 |   int length_; | 
 | 2164 | }; | 
 | 2165 |  | 
 | 2166 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2167 | // Forward declarations. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2168 | const int kStringBuilderConcatHelperLengthBits = 11; | 
 | 2169 | const int kStringBuilderConcatHelperPositionBits = 19; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2170 |  | 
 | 2171 | template <typename schar> | 
 | 2172 | static inline void StringBuilderConcatHelper(String*, | 
 | 2173 |                                              schar*, | 
 | 2174 |                                              FixedArray*, | 
 | 2175 |                                              int); | 
 | 2176 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2177 | typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits> | 
 | 2178 |     StringBuilderSubstringLength; | 
 | 2179 | typedef BitField<int, | 
 | 2180 |                  kStringBuilderConcatHelperLengthBits, | 
 | 2181 |                  kStringBuilderConcatHelperPositionBits> | 
 | 2182 |     StringBuilderSubstringPosition; | 
 | 2183 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2184 |  | 
 | 2185 | class ReplacementStringBuilder { | 
 | 2186 |  public: | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2187 |   ReplacementStringBuilder(Heap* heap, | 
 | 2188 |                            Handle<String> subject, | 
 | 2189 |                            int estimated_part_count) | 
 | 2190 |       : heap_(heap), | 
 | 2191 |         array_builder_(heap->isolate(), estimated_part_count), | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2192 |         subject_(subject), | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2193 |         character_count_(0), | 
 | 2194 |         is_ascii_(subject->IsAsciiRepresentation()) { | 
 | 2195 |     // Require a non-zero initial size. Ensures that doubling the size to | 
 | 2196 |     // extend the array will work. | 
 | 2197 |     ASSERT(estimated_part_count > 0); | 
 | 2198 |   } | 
 | 2199 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2200 |   static inline void AddSubjectSlice(FixedArrayBuilder* builder, | 
 | 2201 |                                      int from, | 
 | 2202 |                                      int to) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2203 |     ASSERT(from >= 0); | 
 | 2204 |     int length = to - from; | 
 | 2205 |     ASSERT(length > 0); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2206 |     if (StringBuilderSubstringLength::is_valid(length) && | 
 | 2207 |         StringBuilderSubstringPosition::is_valid(from)) { | 
 | 2208 |       int encoded_slice = StringBuilderSubstringLength::encode(length) | | 
 | 2209 |           StringBuilderSubstringPosition::encode(from); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2210 |       builder->Add(Smi::FromInt(encoded_slice)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2211 |     } else { | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 2212 |       // Otherwise encode as two smis. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2213 |       builder->Add(Smi::FromInt(-length)); | 
 | 2214 |       builder->Add(Smi::FromInt(from)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2215 |     } | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2216 |   } | 
 | 2217 |  | 
 | 2218 |  | 
 | 2219 |   void EnsureCapacity(int elements) { | 
 | 2220 |     array_builder_.EnsureCapacity(elements); | 
 | 2221 |   } | 
 | 2222 |  | 
 | 2223 |  | 
 | 2224 |   void AddSubjectSlice(int from, int to) { | 
 | 2225 |     AddSubjectSlice(&array_builder_, from, to); | 
 | 2226 |     IncrementCharacterCount(to - from); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2227 |   } | 
 | 2228 |  | 
 | 2229 |  | 
 | 2230 |   void AddString(Handle<String> string) { | 
 | 2231 |     int length = string->length(); | 
 | 2232 |     ASSERT(length > 0); | 
 | 2233 |     AddElement(*string); | 
 | 2234 |     if (!string->IsAsciiRepresentation()) { | 
 | 2235 |       is_ascii_ = false; | 
 | 2236 |     } | 
 | 2237 |     IncrementCharacterCount(length); | 
 | 2238 |   } | 
 | 2239 |  | 
 | 2240 |  | 
 | 2241 |   Handle<String> ToString() { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2242 |     if (array_builder_.length() == 0) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2243 |       return heap_->isolate()->factory()->empty_string(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2244 |     } | 
 | 2245 |  | 
 | 2246 |     Handle<String> joined_string; | 
 | 2247 |     if (is_ascii_) { | 
 | 2248 |       joined_string = NewRawAsciiString(character_count_); | 
 | 2249 |       AssertNoAllocation no_alloc; | 
 | 2250 |       SeqAsciiString* seq = SeqAsciiString::cast(*joined_string); | 
 | 2251 |       char* char_buffer = seq->GetChars(); | 
 | 2252 |       StringBuilderConcatHelper(*subject_, | 
 | 2253 |                                 char_buffer, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2254 |                                 *array_builder_.array(), | 
 | 2255 |                                 array_builder_.length()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2256 |     } else { | 
 | 2257 |       // Non-ASCII. | 
 | 2258 |       joined_string = NewRawTwoByteString(character_count_); | 
 | 2259 |       AssertNoAllocation no_alloc; | 
 | 2260 |       SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string); | 
 | 2261 |       uc16* char_buffer = seq->GetChars(); | 
 | 2262 |       StringBuilderConcatHelper(*subject_, | 
 | 2263 |                                 char_buffer, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2264 |                                 *array_builder_.array(), | 
 | 2265 |                                 array_builder_.length()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2266 |     } | 
 | 2267 |     return joined_string; | 
 | 2268 |   } | 
 | 2269 |  | 
 | 2270 |  | 
 | 2271 |   void IncrementCharacterCount(int by) { | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 2272 |     if (character_count_ > String::kMaxLength - by) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2273 |       V8::FatalProcessOutOfMemory("String.replace result too large."); | 
 | 2274 |     } | 
 | 2275 |     character_count_ += by; | 
 | 2276 |   } | 
 | 2277 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2278 |   Handle<JSArray> GetParts() { | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 2279 |     return array_builder_.ToJSArray(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2280 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2281 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2282 |  private: | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2283 |   Handle<String> NewRawAsciiString(int size) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2284 |     CALL_HEAP_FUNCTION(heap_->isolate(), | 
 | 2285 |                        heap_->AllocateRawAsciiString(size), String); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2286 |   } | 
 | 2287 |  | 
 | 2288 |  | 
 | 2289 |   Handle<String> NewRawTwoByteString(int size) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2290 |     CALL_HEAP_FUNCTION(heap_->isolate(), | 
 | 2291 |                        heap_->AllocateRawTwoByteString(size), String); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2292 |   } | 
 | 2293 |  | 
 | 2294 |  | 
 | 2295 |   void AddElement(Object* element) { | 
 | 2296 |     ASSERT(element->IsSmi() || element->IsString()); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2297 |     ASSERT(array_builder_.capacity() > array_builder_.length()); | 
 | 2298 |     array_builder_.Add(element); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2299 |   } | 
 | 2300 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2301 |   Heap* heap_; | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 2302 |   FixedArrayBuilder array_builder_; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2303 |   Handle<String> subject_; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2304 |   int character_count_; | 
 | 2305 |   bool is_ascii_; | 
 | 2306 | }; | 
 | 2307 |  | 
 | 2308 |  | 
 | 2309 | class CompiledReplacement { | 
 | 2310 |  public: | 
 | 2311 |   CompiledReplacement() | 
 | 2312 |       : parts_(1), replacement_substrings_(0) {} | 
 | 2313 |  | 
 | 2314 |   void Compile(Handle<String> replacement, | 
 | 2315 |                int capture_count, | 
 | 2316 |                int subject_length); | 
 | 2317 |  | 
 | 2318 |   void Apply(ReplacementStringBuilder* builder, | 
 | 2319 |              int match_from, | 
 | 2320 |              int match_to, | 
 | 2321 |              Handle<JSArray> last_match_info); | 
 | 2322 |  | 
 | 2323 |   // Number of distinct parts of the replacement pattern. | 
 | 2324 |   int parts() { | 
 | 2325 |     return parts_.length(); | 
 | 2326 |   } | 
 | 2327 |  private: | 
 | 2328 |   enum PartType { | 
 | 2329 |     SUBJECT_PREFIX = 1, | 
 | 2330 |     SUBJECT_SUFFIX, | 
 | 2331 |     SUBJECT_CAPTURE, | 
 | 2332 |     REPLACEMENT_SUBSTRING, | 
 | 2333 |     REPLACEMENT_STRING, | 
 | 2334 |  | 
 | 2335 |     NUMBER_OF_PART_TYPES | 
 | 2336 |   }; | 
 | 2337 |  | 
 | 2338 |   struct ReplacementPart { | 
 | 2339 |     static inline ReplacementPart SubjectMatch() { | 
 | 2340 |       return ReplacementPart(SUBJECT_CAPTURE, 0); | 
 | 2341 |     } | 
 | 2342 |     static inline ReplacementPart SubjectCapture(int capture_index) { | 
 | 2343 |       return ReplacementPart(SUBJECT_CAPTURE, capture_index); | 
 | 2344 |     } | 
 | 2345 |     static inline ReplacementPart SubjectPrefix() { | 
 | 2346 |       return ReplacementPart(SUBJECT_PREFIX, 0); | 
 | 2347 |     } | 
 | 2348 |     static inline ReplacementPart SubjectSuffix(int subject_length) { | 
 | 2349 |       return ReplacementPart(SUBJECT_SUFFIX, subject_length); | 
 | 2350 |     } | 
 | 2351 |     static inline ReplacementPart ReplacementString() { | 
 | 2352 |       return ReplacementPart(REPLACEMENT_STRING, 0); | 
 | 2353 |     } | 
 | 2354 |     static inline ReplacementPart ReplacementSubString(int from, int to) { | 
 | 2355 |       ASSERT(from >= 0); | 
 | 2356 |       ASSERT(to > from); | 
 | 2357 |       return ReplacementPart(-from, to); | 
 | 2358 |     } | 
 | 2359 |  | 
 | 2360 |     // If tag <= 0 then it is the negation of a start index of a substring of | 
 | 2361 |     // the replacement pattern, otherwise it's a value from PartType. | 
 | 2362 |     ReplacementPart(int tag, int data) | 
 | 2363 |         : tag(tag), data(data) { | 
 | 2364 |       // Must be non-positive or a PartType value. | 
 | 2365 |       ASSERT(tag < NUMBER_OF_PART_TYPES); | 
 | 2366 |     } | 
 | 2367 |     // Either a value of PartType or a non-positive number that is | 
 | 2368 |     // the negation of an index into the replacement string. | 
 | 2369 |     int tag; | 
 | 2370 |     // The data value's interpretation depends on the value of tag: | 
 | 2371 |     // tag == SUBJECT_PREFIX || | 
 | 2372 |     // tag == SUBJECT_SUFFIX:  data is unused. | 
 | 2373 |     // tag == SUBJECT_CAPTURE: data is the number of the capture. | 
 | 2374 |     // tag == REPLACEMENT_SUBSTRING || | 
 | 2375 |     // tag == REPLACEMENT_STRING:    data is index into array of substrings | 
 | 2376 |     //                               of the replacement string. | 
 | 2377 |     // tag <= 0: Temporary representation of the substring of the replacement | 
 | 2378 |     //           string ranging over -tag .. data. | 
 | 2379 |     //           Is replaced by REPLACEMENT_{SUB,}STRING when we create the | 
 | 2380 |     //           substring objects. | 
 | 2381 |     int data; | 
 | 2382 |   }; | 
 | 2383 |  | 
 | 2384 |   template<typename Char> | 
 | 2385 |   static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts, | 
 | 2386 |                                       Vector<Char> characters, | 
 | 2387 |                                       int capture_count, | 
 | 2388 |                                       int subject_length) { | 
 | 2389 |     int length = characters.length(); | 
 | 2390 |     int last = 0; | 
 | 2391 |     for (int i = 0; i < length; i++) { | 
 | 2392 |       Char c = characters[i]; | 
 | 2393 |       if (c == '$') { | 
 | 2394 |         int next_index = i + 1; | 
 | 2395 |         if (next_index == length) {  // No next character! | 
 | 2396 |           break; | 
 | 2397 |         } | 
 | 2398 |         Char c2 = characters[next_index]; | 
 | 2399 |         switch (c2) { | 
 | 2400 |         case '$': | 
 | 2401 |           if (i > last) { | 
 | 2402 |             // There is a substring before. Include the first "$". | 
 | 2403 |             parts->Add(ReplacementPart::ReplacementSubString(last, next_index)); | 
 | 2404 |             last = next_index + 1;  // Continue after the second "$". | 
 | 2405 |           } else { | 
 | 2406 |             // Let the next substring start with the second "$". | 
 | 2407 |             last = next_index; | 
 | 2408 |           } | 
 | 2409 |           i = next_index; | 
 | 2410 |           break; | 
 | 2411 |         case '`': | 
 | 2412 |           if (i > last) { | 
 | 2413 |             parts->Add(ReplacementPart::ReplacementSubString(last, i)); | 
 | 2414 |           } | 
 | 2415 |           parts->Add(ReplacementPart::SubjectPrefix()); | 
 | 2416 |           i = next_index; | 
 | 2417 |           last = i + 1; | 
 | 2418 |           break; | 
 | 2419 |         case '\'': | 
 | 2420 |           if (i > last) { | 
 | 2421 |             parts->Add(ReplacementPart::ReplacementSubString(last, i)); | 
 | 2422 |           } | 
 | 2423 |           parts->Add(ReplacementPart::SubjectSuffix(subject_length)); | 
 | 2424 |           i = next_index; | 
 | 2425 |           last = i + 1; | 
 | 2426 |           break; | 
 | 2427 |         case '&': | 
 | 2428 |           if (i > last) { | 
 | 2429 |             parts->Add(ReplacementPart::ReplacementSubString(last, i)); | 
 | 2430 |           } | 
 | 2431 |           parts->Add(ReplacementPart::SubjectMatch()); | 
 | 2432 |           i = next_index; | 
 | 2433 |           last = i + 1; | 
 | 2434 |           break; | 
 | 2435 |         case '0': | 
 | 2436 |         case '1': | 
 | 2437 |         case '2': | 
 | 2438 |         case '3': | 
 | 2439 |         case '4': | 
 | 2440 |         case '5': | 
 | 2441 |         case '6': | 
 | 2442 |         case '7': | 
 | 2443 |         case '8': | 
 | 2444 |         case '9': { | 
 | 2445 |           int capture_ref = c2 - '0'; | 
 | 2446 |           if (capture_ref > capture_count) { | 
 | 2447 |             i = next_index; | 
 | 2448 |             continue; | 
 | 2449 |           } | 
 | 2450 |           int second_digit_index = next_index + 1; | 
 | 2451 |           if (second_digit_index < length) { | 
 | 2452 |             // Peek ahead to see if we have two digits. | 
 | 2453 |             Char c3 = characters[second_digit_index]; | 
 | 2454 |             if ('0' <= c3 && c3 <= '9') {  // Double digits. | 
 | 2455 |               int double_digit_ref = capture_ref * 10 + c3 - '0'; | 
 | 2456 |               if (double_digit_ref <= capture_count) { | 
 | 2457 |                 next_index = second_digit_index; | 
 | 2458 |                 capture_ref = double_digit_ref; | 
 | 2459 |               } | 
 | 2460 |             } | 
 | 2461 |           } | 
 | 2462 |           if (capture_ref > 0) { | 
 | 2463 |             if (i > last) { | 
 | 2464 |               parts->Add(ReplacementPart::ReplacementSubString(last, i)); | 
 | 2465 |             } | 
 | 2466 |             ASSERT(capture_ref <= capture_count); | 
 | 2467 |             parts->Add(ReplacementPart::SubjectCapture(capture_ref)); | 
 | 2468 |             last = next_index + 1; | 
 | 2469 |           } | 
 | 2470 |           i = next_index; | 
 | 2471 |           break; | 
 | 2472 |         } | 
 | 2473 |         default: | 
 | 2474 |           i = next_index; | 
 | 2475 |           break; | 
 | 2476 |         } | 
 | 2477 |       } | 
 | 2478 |     } | 
 | 2479 |     if (length > last) { | 
 | 2480 |       if (last == 0) { | 
 | 2481 |         parts->Add(ReplacementPart::ReplacementString()); | 
 | 2482 |       } else { | 
 | 2483 |         parts->Add(ReplacementPart::ReplacementSubString(last, length)); | 
 | 2484 |       } | 
 | 2485 |     } | 
 | 2486 |   } | 
 | 2487 |  | 
 | 2488 |   ZoneList<ReplacementPart> parts_; | 
 | 2489 |   ZoneList<Handle<String> > replacement_substrings_; | 
 | 2490 | }; | 
 | 2491 |  | 
 | 2492 |  | 
 | 2493 | void CompiledReplacement::Compile(Handle<String> replacement, | 
 | 2494 |                                   int capture_count, | 
 | 2495 |                                   int subject_length) { | 
 | 2496 |   ASSERT(replacement->IsFlat()); | 
 | 2497 |   if (replacement->IsAsciiRepresentation()) { | 
 | 2498 |     AssertNoAllocation no_alloc; | 
 | 2499 |     ParseReplacementPattern(&parts_, | 
 | 2500 |                             replacement->ToAsciiVector(), | 
 | 2501 |                             capture_count, | 
 | 2502 |                             subject_length); | 
 | 2503 |   } else { | 
 | 2504 |     ASSERT(replacement->IsTwoByteRepresentation()); | 
 | 2505 |     AssertNoAllocation no_alloc; | 
 | 2506 |  | 
 | 2507 |     ParseReplacementPattern(&parts_, | 
 | 2508 |                             replacement->ToUC16Vector(), | 
 | 2509 |                             capture_count, | 
 | 2510 |                             subject_length); | 
 | 2511 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2512 |   Isolate* isolate = replacement->GetIsolate(); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 2513 |   // Find substrings of replacement string and create them as String objects. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2514 |   int substring_index = 0; | 
 | 2515 |   for (int i = 0, n = parts_.length(); i < n; i++) { | 
 | 2516 |     int tag = parts_[i].tag; | 
 | 2517 |     if (tag <= 0) {  // A replacement string slice. | 
 | 2518 |       int from = -tag; | 
 | 2519 |       int to = parts_[i].data; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2520 |       replacement_substrings_.Add( | 
 | 2521 |           isolate->factory()->NewSubString(replacement, from, to)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2522 |       parts_[i].tag = REPLACEMENT_SUBSTRING; | 
 | 2523 |       parts_[i].data = substring_index; | 
 | 2524 |       substring_index++; | 
 | 2525 |     } else if (tag == REPLACEMENT_STRING) { | 
 | 2526 |       replacement_substrings_.Add(replacement); | 
 | 2527 |       parts_[i].data = substring_index; | 
 | 2528 |       substring_index++; | 
 | 2529 |     } | 
 | 2530 |   } | 
 | 2531 | } | 
 | 2532 |  | 
 | 2533 |  | 
 | 2534 | void CompiledReplacement::Apply(ReplacementStringBuilder* builder, | 
 | 2535 |                                 int match_from, | 
 | 2536 |                                 int match_to, | 
 | 2537 |                                 Handle<JSArray> last_match_info) { | 
 | 2538 |   for (int i = 0, n = parts_.length(); i < n; i++) { | 
 | 2539 |     ReplacementPart part = parts_[i]; | 
 | 2540 |     switch (part.tag) { | 
 | 2541 |       case SUBJECT_PREFIX: | 
 | 2542 |         if (match_from > 0) builder->AddSubjectSlice(0, match_from); | 
 | 2543 |         break; | 
 | 2544 |       case SUBJECT_SUFFIX: { | 
 | 2545 |         int subject_length = part.data; | 
 | 2546 |         if (match_to < subject_length) { | 
 | 2547 |           builder->AddSubjectSlice(match_to, subject_length); | 
 | 2548 |         } | 
 | 2549 |         break; | 
 | 2550 |       } | 
 | 2551 |       case SUBJECT_CAPTURE: { | 
 | 2552 |         int capture = part.data; | 
 | 2553 |         FixedArray* match_info = FixedArray::cast(last_match_info->elements()); | 
 | 2554 |         int from = RegExpImpl::GetCapture(match_info, capture * 2); | 
 | 2555 |         int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1); | 
 | 2556 |         if (from >= 0 && to > from) { | 
 | 2557 |           builder->AddSubjectSlice(from, to); | 
 | 2558 |         } | 
 | 2559 |         break; | 
 | 2560 |       } | 
 | 2561 |       case REPLACEMENT_SUBSTRING: | 
 | 2562 |       case REPLACEMENT_STRING: | 
 | 2563 |         builder->AddString(replacement_substrings_[part.data]); | 
 | 2564 |         break; | 
 | 2565 |       default: | 
 | 2566 |         UNREACHABLE(); | 
 | 2567 |     } | 
 | 2568 |   } | 
 | 2569 | } | 
 | 2570 |  | 
 | 2571 |  | 
 | 2572 |  | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 2573 | MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2574 |     Isolate* isolate, | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 2575 |     String* subject, | 
 | 2576 |     JSRegExp* regexp, | 
 | 2577 |     String* replacement, | 
 | 2578 |     JSArray* last_match_info) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2579 |   ASSERT(subject->IsFlat()); | 
 | 2580 |   ASSERT(replacement->IsFlat()); | 
 | 2581 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2582 |   HandleScope handles(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2583 |  | 
 | 2584 |   int length = subject->length(); | 
 | 2585 |   Handle<String> subject_handle(subject); | 
 | 2586 |   Handle<JSRegExp> regexp_handle(regexp); | 
 | 2587 |   Handle<String> replacement_handle(replacement); | 
 | 2588 |   Handle<JSArray> last_match_info_handle(last_match_info); | 
 | 2589 |   Handle<Object> match = RegExpImpl::Exec(regexp_handle, | 
 | 2590 |                                           subject_handle, | 
 | 2591 |                                           0, | 
 | 2592 |                                           last_match_info_handle); | 
 | 2593 |   if (match.is_null()) { | 
 | 2594 |     return Failure::Exception(); | 
 | 2595 |   } | 
 | 2596 |   if (match->IsNull()) { | 
 | 2597 |     return *subject_handle; | 
 | 2598 |   } | 
 | 2599 |  | 
 | 2600 |   int capture_count = regexp_handle->CaptureCount(); | 
 | 2601 |  | 
 | 2602 |   // CompiledReplacement uses zone allocation. | 
 | 2603 |   CompilationZoneScope zone(DELETE_ON_EXIT); | 
 | 2604 |   CompiledReplacement compiled_replacement; | 
 | 2605 |   compiled_replacement.Compile(replacement_handle, | 
 | 2606 |                                capture_count, | 
 | 2607 |                                length); | 
 | 2608 |  | 
 | 2609 |   bool is_global = regexp_handle->GetFlags().is_global(); | 
 | 2610 |  | 
 | 2611 |   // Guessing the number of parts that the final result string is built | 
 | 2612 |   // from. Global regexps can match any number of times, so we guess | 
 | 2613 |   // conservatively. | 
 | 2614 |   int expected_parts = | 
 | 2615 |       (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2616 |   ReplacementStringBuilder builder(isolate->heap(), | 
 | 2617 |                                    subject_handle, | 
 | 2618 |                                    expected_parts); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2619 |  | 
 | 2620 |   // Index of end of last match. | 
 | 2621 |   int prev = 0; | 
 | 2622 |  | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 2623 |   // Number of parts added by compiled replacement plus preceeding | 
 | 2624 |   // string and possibly suffix after last match.  It is possible for | 
 | 2625 |   // all components to use two elements when encoded as two smis. | 
 | 2626 |   const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2627 |   bool matched = true; | 
 | 2628 |   do { | 
 | 2629 |     ASSERT(last_match_info_handle->HasFastElements()); | 
 | 2630 |     // Increase the capacity of the builder before entering local handle-scope, | 
 | 2631 |     // so its internal buffer can safely allocate a new handle if it grows. | 
 | 2632 |     builder.EnsureCapacity(parts_added_per_loop); | 
 | 2633 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2634 |     HandleScope loop_scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2635 |     int start, end; | 
 | 2636 |     { | 
 | 2637 |       AssertNoAllocation match_info_array_is_not_in_a_handle; | 
 | 2638 |       FixedArray* match_info_array = | 
 | 2639 |           FixedArray::cast(last_match_info_handle->elements()); | 
 | 2640 |  | 
 | 2641 |       ASSERT_EQ(capture_count * 2 + 2, | 
 | 2642 |                 RegExpImpl::GetLastCaptureCount(match_info_array)); | 
 | 2643 |       start = RegExpImpl::GetCapture(match_info_array, 0); | 
 | 2644 |       end = RegExpImpl::GetCapture(match_info_array, 1); | 
 | 2645 |     } | 
 | 2646 |  | 
 | 2647 |     if (prev < start) { | 
 | 2648 |       builder.AddSubjectSlice(prev, start); | 
 | 2649 |     } | 
 | 2650 |     compiled_replacement.Apply(&builder, | 
 | 2651 |                                start, | 
 | 2652 |                                end, | 
 | 2653 |                                last_match_info_handle); | 
 | 2654 |     prev = end; | 
 | 2655 |  | 
 | 2656 |     // Only continue checking for global regexps. | 
 | 2657 |     if (!is_global) break; | 
 | 2658 |  | 
 | 2659 |     // Continue from where the match ended, unless it was an empty match. | 
 | 2660 |     int next = end; | 
 | 2661 |     if (start == end) { | 
 | 2662 |       next = end + 1; | 
 | 2663 |       if (next > length) break; | 
 | 2664 |     } | 
 | 2665 |  | 
 | 2666 |     match = RegExpImpl::Exec(regexp_handle, | 
 | 2667 |                              subject_handle, | 
 | 2668 |                              next, | 
 | 2669 |                              last_match_info_handle); | 
 | 2670 |     if (match.is_null()) { | 
 | 2671 |       return Failure::Exception(); | 
 | 2672 |     } | 
 | 2673 |     matched = !match->IsNull(); | 
 | 2674 |   } while (matched); | 
 | 2675 |  | 
 | 2676 |   if (prev < length) { | 
 | 2677 |     builder.AddSubjectSlice(prev, length); | 
 | 2678 |   } | 
 | 2679 |  | 
 | 2680 |   return *(builder.ToString()); | 
 | 2681 | } | 
 | 2682 |  | 
 | 2683 |  | 
| Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 2684 | template <typename ResultSeqString> | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 2685 | MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2686 |     Isolate* isolate, | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 2687 |     String* subject, | 
 | 2688 |     JSRegExp* regexp, | 
 | 2689 |     JSArray* last_match_info) { | 
| Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 2690 |   ASSERT(subject->IsFlat()); | 
 | 2691 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2692 |   HandleScope handles(isolate); | 
| Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 2693 |  | 
 | 2694 |   Handle<String> subject_handle(subject); | 
 | 2695 |   Handle<JSRegExp> regexp_handle(regexp); | 
 | 2696 |   Handle<JSArray> last_match_info_handle(last_match_info); | 
 | 2697 |   Handle<Object> match = RegExpImpl::Exec(regexp_handle, | 
 | 2698 |                                           subject_handle, | 
 | 2699 |                                           0, | 
 | 2700 |                                           last_match_info_handle); | 
 | 2701 |   if (match.is_null()) return Failure::Exception(); | 
 | 2702 |   if (match->IsNull()) return *subject_handle; | 
 | 2703 |  | 
 | 2704 |   ASSERT(last_match_info_handle->HasFastElements()); | 
 | 2705 |  | 
| Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 2706 |   int start, end; | 
 | 2707 |   { | 
 | 2708 |     AssertNoAllocation match_info_array_is_not_in_a_handle; | 
 | 2709 |     FixedArray* match_info_array = | 
 | 2710 |         FixedArray::cast(last_match_info_handle->elements()); | 
 | 2711 |  | 
 | 2712 |     start = RegExpImpl::GetCapture(match_info_array, 0); | 
 | 2713 |     end = RegExpImpl::GetCapture(match_info_array, 1); | 
 | 2714 |   } | 
 | 2715 |  | 
| Steve Block | 053d10c | 2011-06-13 19:13:29 +0100 | [diff] [blame] | 2716 |   int length = subject_handle->length(); | 
| Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 2717 |   int new_length = length - (end - start); | 
 | 2718 |   if (new_length == 0) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2719 |     return isolate->heap()->empty_string(); | 
| Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 2720 |   } | 
 | 2721 |   Handle<ResultSeqString> answer; | 
 | 2722 |   if (ResultSeqString::kHasAsciiEncoding) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2723 |     answer = Handle<ResultSeqString>::cast( | 
 | 2724 |         isolate->factory()->NewRawAsciiString(new_length)); | 
| Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 2725 |   } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2726 |     answer = Handle<ResultSeqString>::cast( | 
 | 2727 |         isolate->factory()->NewRawTwoByteString(new_length)); | 
| Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 2728 |   } | 
 | 2729 |  | 
 | 2730 |   // If the regexp isn't global, only match once. | 
 | 2731 |   if (!regexp_handle->GetFlags().is_global()) { | 
 | 2732 |     if (start > 0) { | 
 | 2733 |       String::WriteToFlat(*subject_handle, | 
 | 2734 |                           answer->GetChars(), | 
 | 2735 |                           0, | 
 | 2736 |                           start); | 
 | 2737 |     } | 
 | 2738 |     if (end < length) { | 
 | 2739 |       String::WriteToFlat(*subject_handle, | 
 | 2740 |                           answer->GetChars() + start, | 
 | 2741 |                           end, | 
 | 2742 |                           length); | 
 | 2743 |     } | 
 | 2744 |     return *answer; | 
 | 2745 |   } | 
 | 2746 |  | 
 | 2747 |   int prev = 0;  // Index of end of last match. | 
 | 2748 |   int next = 0;  // Start of next search (prev unless last match was empty). | 
 | 2749 |   int position = 0; | 
 | 2750 |  | 
 | 2751 |   do { | 
 | 2752 |     if (prev < start) { | 
 | 2753 |       // Add substring subject[prev;start] to answer string. | 
 | 2754 |       String::WriteToFlat(*subject_handle, | 
 | 2755 |                           answer->GetChars() + position, | 
 | 2756 |                           prev, | 
 | 2757 |                           start); | 
 | 2758 |       position += start - prev; | 
 | 2759 |     } | 
 | 2760 |     prev = end; | 
 | 2761 |     next = end; | 
 | 2762 |     // Continue from where the match ended, unless it was an empty match. | 
 | 2763 |     if (start == end) { | 
 | 2764 |       next++; | 
 | 2765 |       if (next > length) break; | 
 | 2766 |     } | 
 | 2767 |     match = RegExpImpl::Exec(regexp_handle, | 
 | 2768 |                              subject_handle, | 
 | 2769 |                              next, | 
 | 2770 |                              last_match_info_handle); | 
 | 2771 |     if (match.is_null()) return Failure::Exception(); | 
 | 2772 |     if (match->IsNull()) break; | 
 | 2773 |  | 
 | 2774 |     ASSERT(last_match_info_handle->HasFastElements()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2775 |     HandleScope loop_scope(isolate); | 
| Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 2776 |     { | 
 | 2777 |       AssertNoAllocation match_info_array_is_not_in_a_handle; | 
 | 2778 |       FixedArray* match_info_array = | 
 | 2779 |           FixedArray::cast(last_match_info_handle->elements()); | 
 | 2780 |       start = RegExpImpl::GetCapture(match_info_array, 0); | 
 | 2781 |       end = RegExpImpl::GetCapture(match_info_array, 1); | 
 | 2782 |     } | 
 | 2783 |   } while (true); | 
 | 2784 |  | 
 | 2785 |   if (prev < length) { | 
 | 2786 |     // Add substring subject[prev;length] to answer string. | 
 | 2787 |     String::WriteToFlat(*subject_handle, | 
 | 2788 |                         answer->GetChars() + position, | 
 | 2789 |                         prev, | 
 | 2790 |                         length); | 
 | 2791 |     position += length - prev; | 
 | 2792 |   } | 
 | 2793 |  | 
 | 2794 |   if (position == 0) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2795 |     return isolate->heap()->empty_string(); | 
| Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 2796 |   } | 
 | 2797 |  | 
 | 2798 |   // Shorten string and fill | 
 | 2799 |   int string_size = ResultSeqString::SizeFor(position); | 
 | 2800 |   int allocated_string_size = ResultSeqString::SizeFor(new_length); | 
 | 2801 |   int delta = allocated_string_size - string_size; | 
 | 2802 |  | 
 | 2803 |   answer->set_length(position); | 
 | 2804 |   if (delta == 0) return *answer; | 
 | 2805 |  | 
 | 2806 |   Address end_of_string = answer->address() + string_size; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2807 |   isolate->heap()->CreateFillerObjectAt(end_of_string, delta); | 
| Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 2808 |  | 
 | 2809 |   return *answer; | 
 | 2810 | } | 
 | 2811 |  | 
 | 2812 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 2813 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2814 |   ASSERT(args.length() == 4); | 
 | 2815 |  | 
 | 2816 |   CONVERT_CHECKED(String, subject, args[0]); | 
 | 2817 |   if (!subject->IsFlat()) { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 2818 |     Object* flat_subject; | 
 | 2819 |     { MaybeObject* maybe_flat_subject = subject->TryFlatten(); | 
 | 2820 |       if (!maybe_flat_subject->ToObject(&flat_subject)) { | 
 | 2821 |         return maybe_flat_subject; | 
 | 2822 |       } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2823 |     } | 
 | 2824 |     subject = String::cast(flat_subject); | 
 | 2825 |   } | 
 | 2826 |  | 
 | 2827 |   CONVERT_CHECKED(String, replacement, args[2]); | 
 | 2828 |   if (!replacement->IsFlat()) { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 2829 |     Object* flat_replacement; | 
 | 2830 |     { MaybeObject* maybe_flat_replacement = replacement->TryFlatten(); | 
 | 2831 |       if (!maybe_flat_replacement->ToObject(&flat_replacement)) { | 
 | 2832 |         return maybe_flat_replacement; | 
 | 2833 |       } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2834 |     } | 
 | 2835 |     replacement = String::cast(flat_replacement); | 
 | 2836 |   } | 
 | 2837 |  | 
 | 2838 |   CONVERT_CHECKED(JSRegExp, regexp, args[1]); | 
 | 2839 |   CONVERT_CHECKED(JSArray, last_match_info, args[3]); | 
 | 2840 |  | 
 | 2841 |   ASSERT(last_match_info->HasFastElements()); | 
 | 2842 |  | 
| Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 2843 |   if (replacement->length() == 0) { | 
 | 2844 |     if (subject->HasOnlyAsciiChars()) { | 
 | 2845 |       return StringReplaceRegExpWithEmptyString<SeqAsciiString>( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2846 |           isolate, subject, regexp, last_match_info); | 
| Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 2847 |     } else { | 
 | 2848 |       return StringReplaceRegExpWithEmptyString<SeqTwoByteString>( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2849 |           isolate, subject, regexp, last_match_info); | 
| Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 2850 |     } | 
 | 2851 |   } | 
 | 2852 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2853 |   return StringReplaceRegExpWithString(isolate, | 
 | 2854 |                                        subject, | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2855 |                                        regexp, | 
 | 2856 |                                        replacement, | 
 | 2857 |                                        last_match_info); | 
 | 2858 | } | 
 | 2859 |  | 
 | 2860 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2861 | // Perform string match of pattern on subject, starting at start index. | 
 | 2862 | // Caller must ensure that 0 <= start_index <= sub->length(), | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 2863 | // and should check that pat->length() + start_index <= sub->length(). | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2864 | int Runtime::StringMatch(Isolate* isolate, | 
 | 2865 |                          Handle<String> sub, | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2866 |                          Handle<String> pat, | 
 | 2867 |                          int start_index) { | 
 | 2868 |   ASSERT(0 <= start_index); | 
 | 2869 |   ASSERT(start_index <= sub->length()); | 
 | 2870 |  | 
 | 2871 |   int pattern_length = pat->length(); | 
 | 2872 |   if (pattern_length == 0) return start_index; | 
 | 2873 |  | 
 | 2874 |   int subject_length = sub->length(); | 
 | 2875 |   if (start_index + pattern_length > subject_length) return -1; | 
 | 2876 |  | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 2877 |   if (!sub->IsFlat()) FlattenString(sub); | 
 | 2878 |   if (!pat->IsFlat()) FlattenString(pat); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2879 |  | 
 | 2880 |   AssertNoAllocation no_heap_allocation;  // ensure vectors stay valid | 
| Steve Block | 8defd9f | 2010-07-08 12:39:36 +0100 | [diff] [blame] | 2881 |   // Extract flattened substrings of cons strings before determining asciiness. | 
 | 2882 |   String* seq_sub = *sub; | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 2883 |   if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first(); | 
| Steve Block | 8defd9f | 2010-07-08 12:39:36 +0100 | [diff] [blame] | 2884 |   String* seq_pat = *pat; | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 2885 |   if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first(); | 
| Steve Block | 8defd9f | 2010-07-08 12:39:36 +0100 | [diff] [blame] | 2886 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2887 |   // dispatch on type of strings | 
| Steve Block | 8defd9f | 2010-07-08 12:39:36 +0100 | [diff] [blame] | 2888 |   if (seq_pat->IsAsciiRepresentation()) { | 
 | 2889 |     Vector<const char> pat_vector = seq_pat->ToAsciiVector(); | 
 | 2890 |     if (seq_sub->IsAsciiRepresentation()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2891 |       return SearchString(isolate, | 
 | 2892 |                           seq_sub->ToAsciiVector(), | 
 | 2893 |                           pat_vector, | 
 | 2894 |                           start_index); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2895 |     } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2896 |     return SearchString(isolate, | 
 | 2897 |                         seq_sub->ToUC16Vector(), | 
 | 2898 |                         pat_vector, | 
 | 2899 |                         start_index); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2900 |   } | 
| Steve Block | 8defd9f | 2010-07-08 12:39:36 +0100 | [diff] [blame] | 2901 |   Vector<const uc16> pat_vector = seq_pat->ToUC16Vector(); | 
 | 2902 |   if (seq_sub->IsAsciiRepresentation()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2903 |     return SearchString(isolate, | 
 | 2904 |                         seq_sub->ToAsciiVector(), | 
 | 2905 |                         pat_vector, | 
 | 2906 |                         start_index); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2907 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2908 |   return SearchString(isolate, | 
 | 2909 |                       seq_sub->ToUC16Vector(), | 
 | 2910 |                       pat_vector, | 
 | 2911 |                       start_index); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2912 | } | 
 | 2913 |  | 
 | 2914 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 2915 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2916 |   HandleScope scope(isolate);  // create a new handle scope | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2917 |   ASSERT(args.length() == 3); | 
 | 2918 |  | 
 | 2919 |   CONVERT_ARG_CHECKED(String, sub, 0); | 
 | 2920 |   CONVERT_ARG_CHECKED(String, pat, 1); | 
 | 2921 |  | 
 | 2922 |   Object* index = args[2]; | 
 | 2923 |   uint32_t start_index; | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 2924 |   if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2925 |  | 
 | 2926 |   RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length())); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2927 |   int position = | 
 | 2928 |       Runtime::StringMatch(isolate, sub, pat, start_index); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2929 |   return Smi::FromInt(position); | 
 | 2930 | } | 
 | 2931 |  | 
 | 2932 |  | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 2933 | template <typename schar, typename pchar> | 
| Steve Block | 5915150 | 2010-09-22 15:07:15 +0100 | [diff] [blame] | 2934 | static int StringMatchBackwards(Vector<const schar> subject, | 
 | 2935 |                                 Vector<const pchar> pattern, | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 2936 |                                 int idx) { | 
| Steve Block | 5915150 | 2010-09-22 15:07:15 +0100 | [diff] [blame] | 2937 |   int pattern_length = pattern.length(); | 
 | 2938 |   ASSERT(pattern_length >= 1); | 
 | 2939 |   ASSERT(idx + pattern_length <= subject.length()); | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 2940 |  | 
 | 2941 |   if (sizeof(schar) == 1 && sizeof(pchar) > 1) { | 
| Steve Block | 5915150 | 2010-09-22 15:07:15 +0100 | [diff] [blame] | 2942 |     for (int i = 0; i < pattern_length; i++) { | 
 | 2943 |       uc16 c = pattern[i]; | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 2944 |       if (c > String::kMaxAsciiCharCode) { | 
 | 2945 |         return -1; | 
 | 2946 |       } | 
 | 2947 |     } | 
 | 2948 |   } | 
 | 2949 |  | 
| Steve Block | 5915150 | 2010-09-22 15:07:15 +0100 | [diff] [blame] | 2950 |   pchar pattern_first_char = pattern[0]; | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 2951 |   for (int i = idx; i >= 0; i--) { | 
| Steve Block | 5915150 | 2010-09-22 15:07:15 +0100 | [diff] [blame] | 2952 |     if (subject[i] != pattern_first_char) continue; | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 2953 |     int j = 1; | 
| Steve Block | 5915150 | 2010-09-22 15:07:15 +0100 | [diff] [blame] | 2954 |     while (j < pattern_length) { | 
 | 2955 |       if (pattern[j] != subject[i+j]) { | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 2956 |         break; | 
 | 2957 |       } | 
 | 2958 |       j++; | 
 | 2959 |     } | 
| Steve Block | 5915150 | 2010-09-22 15:07:15 +0100 | [diff] [blame] | 2960 |     if (j == pattern_length) { | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 2961 |       return i; | 
 | 2962 |     } | 
 | 2963 |   } | 
 | 2964 |   return -1; | 
 | 2965 | } | 
 | 2966 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 2967 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 2968 |   HandleScope scope(isolate);  // create a new handle scope | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2969 |   ASSERT(args.length() == 3); | 
 | 2970 |  | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 2971 |   CONVERT_ARG_CHECKED(String, sub, 0); | 
 | 2972 |   CONVERT_ARG_CHECKED(String, pat, 1); | 
 | 2973 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2974 |   Object* index = args[2]; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2975 |   uint32_t start_index; | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 2976 |   if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2977 |  | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 2978 |   uint32_t pat_length = pat->length(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2979 |   uint32_t sub_length = sub->length(); | 
 | 2980 |  | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 2981 |   if (start_index + pat_length > sub_length) { | 
 | 2982 |     start_index = sub_length - pat_length; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 2983 |   } | 
 | 2984 |  | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 2985 |   if (pat_length == 0) { | 
 | 2986 |     return Smi::FromInt(start_index); | 
 | 2987 |   } | 
 | 2988 |  | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 2989 |   if (!sub->IsFlat()) FlattenString(sub); | 
 | 2990 |   if (!pat->IsFlat()) FlattenString(pat); | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 2991 |  | 
 | 2992 |   AssertNoAllocation no_heap_allocation;  // ensure vectors stay valid | 
 | 2993 |  | 
 | 2994 |   int position = -1; | 
 | 2995 |  | 
 | 2996 |   if (pat->IsAsciiRepresentation()) { | 
 | 2997 |     Vector<const char> pat_vector = pat->ToAsciiVector(); | 
 | 2998 |     if (sub->IsAsciiRepresentation()) { | 
 | 2999 |       position = StringMatchBackwards(sub->ToAsciiVector(), | 
 | 3000 |                                       pat_vector, | 
 | 3001 |                                       start_index); | 
 | 3002 |     } else { | 
 | 3003 |       position = StringMatchBackwards(sub->ToUC16Vector(), | 
 | 3004 |                                       pat_vector, | 
 | 3005 |                                       start_index); | 
 | 3006 |     } | 
 | 3007 |   } else { | 
 | 3008 |     Vector<const uc16> pat_vector = pat->ToUC16Vector(); | 
 | 3009 |     if (sub->IsAsciiRepresentation()) { | 
 | 3010 |       position = StringMatchBackwards(sub->ToAsciiVector(), | 
 | 3011 |                                       pat_vector, | 
 | 3012 |                                       start_index); | 
 | 3013 |     } else { | 
 | 3014 |       position = StringMatchBackwards(sub->ToUC16Vector(), | 
 | 3015 |                                       pat_vector, | 
 | 3016 |                                       start_index); | 
 | 3017 |     } | 
 | 3018 |   } | 
 | 3019 |  | 
 | 3020 |   return Smi::FromInt(position); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3021 | } | 
 | 3022 |  | 
 | 3023 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 3024 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3025 |   NoHandleAllocation ha; | 
 | 3026 |   ASSERT(args.length() == 2); | 
 | 3027 |  | 
 | 3028 |   CONVERT_CHECKED(String, str1, args[0]); | 
 | 3029 |   CONVERT_CHECKED(String, str2, args[1]); | 
 | 3030 |  | 
 | 3031 |   if (str1 == str2) return Smi::FromInt(0);  // Equal. | 
 | 3032 |   int str1_length = str1->length(); | 
 | 3033 |   int str2_length = str2->length(); | 
 | 3034 |  | 
 | 3035 |   // Decide trivial cases without flattening. | 
 | 3036 |   if (str1_length == 0) { | 
 | 3037 |     if (str2_length == 0) return Smi::FromInt(0);  // Equal. | 
 | 3038 |     return Smi::FromInt(-str2_length); | 
 | 3039 |   } else { | 
 | 3040 |     if (str2_length == 0) return Smi::FromInt(str1_length); | 
 | 3041 |   } | 
 | 3042 |  | 
 | 3043 |   int end = str1_length < str2_length ? str1_length : str2_length; | 
 | 3044 |  | 
 | 3045 |   // No need to flatten if we are going to find the answer on the first | 
 | 3046 |   // character.  At this point we know there is at least one character | 
 | 3047 |   // in each string, due to the trivial case handling above. | 
 | 3048 |   int d = str1->Get(0) - str2->Get(0); | 
 | 3049 |   if (d != 0) return Smi::FromInt(d); | 
 | 3050 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3051 |   str1->TryFlatten(); | 
 | 3052 |   str2->TryFlatten(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3053 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3054 |   StringInputBuffer& buf1 = | 
 | 3055 |       *isolate->runtime_state()->string_locale_compare_buf1(); | 
 | 3056 |   StringInputBuffer& buf2 = | 
 | 3057 |       *isolate->runtime_state()->string_locale_compare_buf2(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3058 |  | 
 | 3059 |   buf1.Reset(str1); | 
 | 3060 |   buf2.Reset(str2); | 
 | 3061 |  | 
 | 3062 |   for (int i = 0; i < end; i++) { | 
 | 3063 |     uint16_t char1 = buf1.GetNext(); | 
 | 3064 |     uint16_t char2 = buf2.GetNext(); | 
 | 3065 |     if (char1 != char2) return Smi::FromInt(char1 - char2); | 
 | 3066 |   } | 
 | 3067 |  | 
 | 3068 |   return Smi::FromInt(str1_length - str2_length); | 
 | 3069 | } | 
 | 3070 |  | 
 | 3071 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 3072 | RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3073 |   NoHandleAllocation ha; | 
 | 3074 |   ASSERT(args.length() == 3); | 
 | 3075 |  | 
 | 3076 |   CONVERT_CHECKED(String, value, args[0]); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 3077 |   Object* from = args[1]; | 
 | 3078 |   Object* to = args[2]; | 
 | 3079 |   int start, end; | 
 | 3080 |   // We have a fast integer-only case here to avoid a conversion to double in | 
 | 3081 |   // the common case where from and to are Smis. | 
 | 3082 |   if (from->IsSmi() && to->IsSmi()) { | 
 | 3083 |     start = Smi::cast(from)->value(); | 
 | 3084 |     end = Smi::cast(to)->value(); | 
 | 3085 |   } else { | 
 | 3086 |     CONVERT_DOUBLE_CHECKED(from_number, from); | 
 | 3087 |     CONVERT_DOUBLE_CHECKED(to_number, to); | 
 | 3088 |     start = FastD2I(from_number); | 
 | 3089 |     end = FastD2I(to_number); | 
 | 3090 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3091 |   RUNTIME_ASSERT(end >= start); | 
 | 3092 |   RUNTIME_ASSERT(start >= 0); | 
 | 3093 |   RUNTIME_ASSERT(end <= value->length()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3094 |   isolate->counters()->sub_string_runtime()->Increment(); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 3095 |   return value->SubString(start, end); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3096 | } | 
 | 3097 |  | 
 | 3098 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 3099 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3100 |   ASSERT_EQ(3, args.length()); | 
 | 3101 |  | 
 | 3102 |   CONVERT_ARG_CHECKED(String, subject, 0); | 
 | 3103 |   CONVERT_ARG_CHECKED(JSRegExp, regexp, 1); | 
 | 3104 |   CONVERT_ARG_CHECKED(JSArray, regexp_info, 2); | 
 | 3105 |   HandleScope handles; | 
 | 3106 |  | 
 | 3107 |   Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info); | 
 | 3108 |  | 
 | 3109 |   if (match.is_null()) { | 
 | 3110 |     return Failure::Exception(); | 
 | 3111 |   } | 
 | 3112 |   if (match->IsNull()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3113 |     return isolate->heap()->null_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3114 |   } | 
 | 3115 |   int length = subject->length(); | 
 | 3116 |  | 
 | 3117 |   CompilationZoneScope zone_space(DELETE_ON_EXIT); | 
 | 3118 |   ZoneList<int> offsets(8); | 
 | 3119 |   do { | 
 | 3120 |     int start; | 
 | 3121 |     int end; | 
 | 3122 |     { | 
 | 3123 |       AssertNoAllocation no_alloc; | 
 | 3124 |       FixedArray* elements = FixedArray::cast(regexp_info->elements()); | 
 | 3125 |       start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value(); | 
 | 3126 |       end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value(); | 
 | 3127 |     } | 
 | 3128 |     offsets.Add(start); | 
 | 3129 |     offsets.Add(end); | 
 | 3130 |     int index = start < end ? end : end + 1; | 
 | 3131 |     if (index > length) break; | 
 | 3132 |     match = RegExpImpl::Exec(regexp, subject, index, regexp_info); | 
 | 3133 |     if (match.is_null()) { | 
 | 3134 |       return Failure::Exception(); | 
 | 3135 |     } | 
 | 3136 |   } while (!match->IsNull()); | 
 | 3137 |   int matches = offsets.length() / 2; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3138 |   Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3139 |   for (int i = 0; i < matches ; i++) { | 
 | 3140 |     int from = offsets.at(i * 2); | 
 | 3141 |     int to = offsets.at(i * 2 + 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3142 |     Handle<String> match = isolate->factory()->NewSubString(subject, from, to); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 3143 |     elements->set(i, *match); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3144 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3145 |   Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3146 |   result->set_length(Smi::FromInt(matches)); | 
 | 3147 |   return *result; | 
 | 3148 | } | 
 | 3149 |  | 
 | 3150 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3151 | // Two smis before and after the match, for very long strings. | 
 | 3152 | const int kMaxBuilderEntriesPerRegExpMatch = 5; | 
 | 3153 |  | 
 | 3154 |  | 
 | 3155 | static void SetLastMatchInfoNoCaptures(Handle<String> subject, | 
 | 3156 |                                        Handle<JSArray> last_match_info, | 
 | 3157 |                                        int match_start, | 
 | 3158 |                                        int match_end) { | 
 | 3159 |   // Fill last_match_info with a single capture. | 
 | 3160 |   last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead); | 
 | 3161 |   AssertNoAllocation no_gc; | 
 | 3162 |   FixedArray* elements = FixedArray::cast(last_match_info->elements()); | 
 | 3163 |   RegExpImpl::SetLastCaptureCount(elements, 2); | 
 | 3164 |   RegExpImpl::SetLastInput(elements, *subject); | 
 | 3165 |   RegExpImpl::SetLastSubject(elements, *subject); | 
 | 3166 |   RegExpImpl::SetCapture(elements, 0, match_start); | 
 | 3167 |   RegExpImpl::SetCapture(elements, 1, match_end); | 
 | 3168 | } | 
 | 3169 |  | 
 | 3170 |  | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 3171 | template <typename SubjectChar, typename PatternChar> | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3172 | static bool SearchStringMultiple(Isolate* isolate, | 
 | 3173 |                                  Vector<const SubjectChar> subject, | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 3174 |                                  Vector<const PatternChar> pattern, | 
 | 3175 |                                  String* pattern_string, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3176 |                                  FixedArrayBuilder* builder, | 
 | 3177 |                                  int* match_pos) { | 
 | 3178 |   int pos = *match_pos; | 
 | 3179 |   int subject_length = subject.length(); | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 3180 |   int pattern_length = pattern.length(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3181 |   int max_search_start = subject_length - pattern_length; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3182 |   StringSearch<PatternChar, SubjectChar> search(isolate, pattern); | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 3183 |   while (pos <= max_search_start) { | 
 | 3184 |     if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { | 
 | 3185 |       *match_pos = pos; | 
 | 3186 |       return false; | 
 | 3187 |     } | 
 | 3188 |     // Position of end of previous match. | 
 | 3189 |     int match_end = pos + pattern_length; | 
 | 3190 |     int new_pos = search.Search(subject, match_end); | 
 | 3191 |     if (new_pos >= 0) { | 
 | 3192 |       // A match. | 
 | 3193 |       if (new_pos > match_end) { | 
 | 3194 |         ReplacementStringBuilder::AddSubjectSlice(builder, | 
 | 3195 |             match_end, | 
 | 3196 |             new_pos); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3197 |       } | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 3198 |       pos = new_pos; | 
 | 3199 |       builder->Add(pattern_string); | 
 | 3200 |     } else { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3201 |       break; | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 3202 |     } | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3203 |   } | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 3204 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3205 |   if (pos < max_search_start) { | 
 | 3206 |     ReplacementStringBuilder::AddSubjectSlice(builder, | 
 | 3207 |                                               pos + pattern_length, | 
 | 3208 |                                               subject_length); | 
 | 3209 |   } | 
 | 3210 |   *match_pos = pos; | 
 | 3211 |   return true; | 
 | 3212 | } | 
 | 3213 |  | 
 | 3214 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3215 | static bool SearchStringMultiple(Isolate* isolate, | 
 | 3216 |                                  Handle<String> subject, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3217 |                                  Handle<String> pattern, | 
 | 3218 |                                  Handle<JSArray> last_match_info, | 
 | 3219 |                                  FixedArrayBuilder* builder) { | 
 | 3220 |   ASSERT(subject->IsFlat()); | 
 | 3221 |   ASSERT(pattern->IsFlat()); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3222 |  | 
 | 3223 |   // Treating as if a previous match was before first character. | 
 | 3224 |   int match_pos = -pattern->length(); | 
 | 3225 |  | 
 | 3226 |   for (;;) {  // Break when search complete. | 
 | 3227 |     builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); | 
 | 3228 |     AssertNoAllocation no_gc; | 
 | 3229 |     if (subject->IsAsciiRepresentation()) { | 
 | 3230 |       Vector<const char> subject_vector = subject->ToAsciiVector(); | 
 | 3231 |       if (pattern->IsAsciiRepresentation()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3232 |         if (SearchStringMultiple(isolate, | 
 | 3233 |                                  subject_vector, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3234 |                                  pattern->ToAsciiVector(), | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 3235 |                                  *pattern, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3236 |                                  builder, | 
 | 3237 |                                  &match_pos)) break; | 
 | 3238 |       } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3239 |         if (SearchStringMultiple(isolate, | 
 | 3240 |                                  subject_vector, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3241 |                                  pattern->ToUC16Vector(), | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 3242 |                                  *pattern, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3243 |                                  builder, | 
 | 3244 |                                  &match_pos)) break; | 
 | 3245 |       } | 
 | 3246 |     } else { | 
 | 3247 |       Vector<const uc16> subject_vector = subject->ToUC16Vector(); | 
 | 3248 |       if (pattern->IsAsciiRepresentation()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3249 |         if (SearchStringMultiple(isolate, | 
 | 3250 |                                  subject_vector, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3251 |                                  pattern->ToAsciiVector(), | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 3252 |                                  *pattern, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3253 |                                  builder, | 
 | 3254 |                                  &match_pos)) break; | 
 | 3255 |       } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3256 |         if (SearchStringMultiple(isolate, | 
 | 3257 |                                  subject_vector, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3258 |                                  pattern->ToUC16Vector(), | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 3259 |                                  *pattern, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3260 |                                  builder, | 
 | 3261 |                                  &match_pos)) break; | 
 | 3262 |       } | 
 | 3263 |     } | 
 | 3264 |   } | 
 | 3265 |  | 
 | 3266 |   if (match_pos >= 0) { | 
 | 3267 |     SetLastMatchInfoNoCaptures(subject, | 
 | 3268 |                                last_match_info, | 
 | 3269 |                                match_pos, | 
 | 3270 |                                match_pos + pattern->length()); | 
 | 3271 |     return true; | 
 | 3272 |   } | 
 | 3273 |   return false;  // No matches at all. | 
 | 3274 | } | 
 | 3275 |  | 
 | 3276 |  | 
 | 3277 | static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3278 |     Isolate* isolate, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3279 |     Handle<String> subject, | 
 | 3280 |     Handle<JSRegExp> regexp, | 
 | 3281 |     Handle<JSArray> last_match_array, | 
 | 3282 |     FixedArrayBuilder* builder) { | 
 | 3283 |   ASSERT(subject->IsFlat()); | 
 | 3284 |   int match_start = -1; | 
 | 3285 |   int match_end = 0; | 
 | 3286 |   int pos = 0; | 
 | 3287 |   int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); | 
 | 3288 |   if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; | 
 | 3289 |  | 
 | 3290 |   OffsetsVector registers(required_registers); | 
| Steve Block | 791712a | 2010-08-27 10:21:07 +0100 | [diff] [blame] | 3291 |   Vector<int32_t> register_vector(registers.vector(), registers.length()); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3292 |   int subject_length = subject->length(); | 
 | 3293 |  | 
 | 3294 |   for (;;) {  // Break on failure, return on exception. | 
 | 3295 |     RegExpImpl::IrregexpResult result = | 
 | 3296 |         RegExpImpl::IrregexpExecOnce(regexp, | 
 | 3297 |                                      subject, | 
 | 3298 |                                      pos, | 
 | 3299 |                                      register_vector); | 
 | 3300 |     if (result == RegExpImpl::RE_SUCCESS) { | 
 | 3301 |       match_start = register_vector[0]; | 
 | 3302 |       builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); | 
 | 3303 |       if (match_end < match_start) { | 
 | 3304 |         ReplacementStringBuilder::AddSubjectSlice(builder, | 
 | 3305 |                                                   match_end, | 
 | 3306 |                                                   match_start); | 
 | 3307 |       } | 
 | 3308 |       match_end = register_vector[1]; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3309 |       HandleScope loop_scope(isolate); | 
 | 3310 |       builder->Add(*isolate->factory()->NewSubString(subject, | 
 | 3311 |                                                      match_start, | 
 | 3312 |                                                      match_end)); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3313 |       if (match_start != match_end) { | 
 | 3314 |         pos = match_end; | 
 | 3315 |       } else { | 
 | 3316 |         pos = match_end + 1; | 
 | 3317 |         if (pos > subject_length) break; | 
 | 3318 |       } | 
 | 3319 |     } else if (result == RegExpImpl::RE_FAILURE) { | 
 | 3320 |       break; | 
 | 3321 |     } else { | 
 | 3322 |       ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); | 
 | 3323 |       return result; | 
 | 3324 |     } | 
 | 3325 |   } | 
 | 3326 |  | 
 | 3327 |   if (match_start >= 0) { | 
 | 3328 |     if (match_end < subject_length) { | 
 | 3329 |       ReplacementStringBuilder::AddSubjectSlice(builder, | 
 | 3330 |                                                 match_end, | 
 | 3331 |                                                 subject_length); | 
 | 3332 |     } | 
 | 3333 |     SetLastMatchInfoNoCaptures(subject, | 
 | 3334 |                                last_match_array, | 
 | 3335 |                                match_start, | 
 | 3336 |                                match_end); | 
 | 3337 |     return RegExpImpl::RE_SUCCESS; | 
 | 3338 |   } else { | 
 | 3339 |     return RegExpImpl::RE_FAILURE;  // No matches at all. | 
 | 3340 |   } | 
 | 3341 | } | 
 | 3342 |  | 
 | 3343 |  | 
 | 3344 | static RegExpImpl::IrregexpResult SearchRegExpMultiple( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3345 |     Isolate* isolate, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3346 |     Handle<String> subject, | 
 | 3347 |     Handle<JSRegExp> regexp, | 
 | 3348 |     Handle<JSArray> last_match_array, | 
 | 3349 |     FixedArrayBuilder* builder) { | 
 | 3350 |  | 
 | 3351 |   ASSERT(subject->IsFlat()); | 
 | 3352 |   int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); | 
 | 3353 |   if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; | 
 | 3354 |  | 
 | 3355 |   OffsetsVector registers(required_registers); | 
| Steve Block | 791712a | 2010-08-27 10:21:07 +0100 | [diff] [blame] | 3356 |   Vector<int32_t> register_vector(registers.vector(), registers.length()); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3357 |  | 
 | 3358 |   RegExpImpl::IrregexpResult result = | 
 | 3359 |       RegExpImpl::IrregexpExecOnce(regexp, | 
 | 3360 |                                    subject, | 
 | 3361 |                                    0, | 
 | 3362 |                                    register_vector); | 
 | 3363 |  | 
 | 3364 |   int capture_count = regexp->CaptureCount(); | 
 | 3365 |   int subject_length = subject->length(); | 
 | 3366 |  | 
 | 3367 |   // Position to search from. | 
 | 3368 |   int pos = 0; | 
 | 3369 |   // End of previous match. Differs from pos if match was empty. | 
 | 3370 |   int match_end = 0; | 
 | 3371 |   if (result == RegExpImpl::RE_SUCCESS) { | 
 | 3372 |     // Need to keep a copy of the previous match for creating last_match_info | 
 | 3373 |     // at the end, so we have two vectors that we swap between. | 
 | 3374 |     OffsetsVector registers2(required_registers); | 
 | 3375 |     Vector<int> prev_register_vector(registers2.vector(), registers2.length()); | 
 | 3376 |  | 
 | 3377 |     do { | 
 | 3378 |       int match_start = register_vector[0]; | 
 | 3379 |       builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); | 
 | 3380 |       if (match_end < match_start) { | 
 | 3381 |         ReplacementStringBuilder::AddSubjectSlice(builder, | 
 | 3382 |                                                   match_end, | 
 | 3383 |                                                   match_start); | 
 | 3384 |       } | 
 | 3385 |       match_end = register_vector[1]; | 
 | 3386 |  | 
 | 3387 |       { | 
 | 3388 |         // Avoid accumulating new handles inside loop. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3389 |         HandleScope temp_scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3390 |         // Arguments array to replace function is match, captures, index and | 
 | 3391 |         // subject, i.e., 3 + capture count in total. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3392 |         Handle<FixedArray> elements = | 
 | 3393 |             isolate->factory()->NewFixedArray(3 + capture_count); | 
 | 3394 |         Handle<String> match = isolate->factory()->NewSubString(subject, | 
 | 3395 |                                                                 match_start, | 
 | 3396 |                                                                 match_end); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 3397 |         elements->set(0, *match); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3398 |         for (int i = 1; i <= capture_count; i++) { | 
 | 3399 |           int start = register_vector[i * 2]; | 
 | 3400 |           if (start >= 0) { | 
 | 3401 |             int end = register_vector[i * 2 + 1]; | 
 | 3402 |             ASSERT(start <= end); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3403 |             Handle<String> substring = isolate->factory()->NewSubString(subject, | 
 | 3404 |                                                                         start, | 
 | 3405 |                                                                         end); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3406 |             elements->set(i, *substring); | 
 | 3407 |           } else { | 
 | 3408 |             ASSERT(register_vector[i * 2 + 1] < 0); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3409 |             elements->set(i, isolate->heap()->undefined_value()); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3410 |           } | 
 | 3411 |         } | 
 | 3412 |         elements->set(capture_count + 1, Smi::FromInt(match_start)); | 
 | 3413 |         elements->set(capture_count + 2, *subject); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3414 |         builder->Add(*isolate->factory()->NewJSArrayWithElements(elements)); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3415 |       } | 
 | 3416 |       // Swap register vectors, so the last successful match is in | 
 | 3417 |       // prev_register_vector. | 
| Steve Block | 791712a | 2010-08-27 10:21:07 +0100 | [diff] [blame] | 3418 |       Vector<int32_t> tmp = prev_register_vector; | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3419 |       prev_register_vector = register_vector; | 
 | 3420 |       register_vector = tmp; | 
 | 3421 |  | 
 | 3422 |       if (match_end > match_start) { | 
 | 3423 |         pos = match_end; | 
 | 3424 |       } else { | 
 | 3425 |         pos = match_end + 1; | 
 | 3426 |         if (pos > subject_length) { | 
 | 3427 |           break; | 
 | 3428 |         } | 
 | 3429 |       } | 
 | 3430 |  | 
 | 3431 |       result = RegExpImpl::IrregexpExecOnce(regexp, | 
 | 3432 |                                             subject, | 
 | 3433 |                                             pos, | 
 | 3434 |                                             register_vector); | 
 | 3435 |     } while (result == RegExpImpl::RE_SUCCESS); | 
 | 3436 |  | 
 | 3437 |     if (result != RegExpImpl::RE_EXCEPTION) { | 
 | 3438 |       // Finished matching, with at least one match. | 
 | 3439 |       if (match_end < subject_length) { | 
 | 3440 |         ReplacementStringBuilder::AddSubjectSlice(builder, | 
 | 3441 |                                                   match_end, | 
 | 3442 |                                                   subject_length); | 
 | 3443 |       } | 
 | 3444 |  | 
 | 3445 |       int last_match_capture_count = (capture_count + 1) * 2; | 
 | 3446 |       int last_match_array_size = | 
 | 3447 |           last_match_capture_count + RegExpImpl::kLastMatchOverhead; | 
 | 3448 |       last_match_array->EnsureSize(last_match_array_size); | 
 | 3449 |       AssertNoAllocation no_gc; | 
 | 3450 |       FixedArray* elements = FixedArray::cast(last_match_array->elements()); | 
 | 3451 |       RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count); | 
 | 3452 |       RegExpImpl::SetLastSubject(elements, *subject); | 
 | 3453 |       RegExpImpl::SetLastInput(elements, *subject); | 
 | 3454 |       for (int i = 0; i < last_match_capture_count; i++) { | 
 | 3455 |         RegExpImpl::SetCapture(elements, i, prev_register_vector[i]); | 
 | 3456 |       } | 
 | 3457 |       return RegExpImpl::RE_SUCCESS; | 
 | 3458 |     } | 
 | 3459 |   } | 
 | 3460 |   // No matches at all, return failure or exception result directly. | 
 | 3461 |   return result; | 
 | 3462 | } | 
 | 3463 |  | 
 | 3464 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 3465 | RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3466 |   ASSERT(args.length() == 4); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3467 |   HandleScope handles(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3468 |  | 
 | 3469 |   CONVERT_ARG_CHECKED(String, subject, 1); | 
 | 3470 |   if (!subject->IsFlat()) { FlattenString(subject); } | 
 | 3471 |   CONVERT_ARG_CHECKED(JSRegExp, regexp, 0); | 
 | 3472 |   CONVERT_ARG_CHECKED(JSArray, last_match_info, 2); | 
 | 3473 |   CONVERT_ARG_CHECKED(JSArray, result_array, 3); | 
 | 3474 |  | 
 | 3475 |   ASSERT(last_match_info->HasFastElements()); | 
 | 3476 |   ASSERT(regexp->GetFlags().is_global()); | 
 | 3477 |   Handle<FixedArray> result_elements; | 
 | 3478 |   if (result_array->HasFastElements()) { | 
 | 3479 |     result_elements = | 
 | 3480 |         Handle<FixedArray>(FixedArray::cast(result_array->elements())); | 
 | 3481 |   } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3482 |     result_elements = isolate->factory()->NewFixedArrayWithHoles(16); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3483 |   } | 
 | 3484 |   FixedArrayBuilder builder(result_elements); | 
 | 3485 |  | 
 | 3486 |   if (regexp->TypeTag() == JSRegExp::ATOM) { | 
 | 3487 |     Handle<String> pattern( | 
 | 3488 |         String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex))); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 3489 |     ASSERT(pattern->IsFlat()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3490 |     if (SearchStringMultiple(isolate, subject, pattern, | 
 | 3491 |                              last_match_info, &builder)) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3492 |       return *builder.ToJSArray(result_array); | 
 | 3493 |     } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3494 |     return isolate->heap()->null_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3495 |   } | 
 | 3496 |  | 
 | 3497 |   ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP); | 
 | 3498 |  | 
 | 3499 |   RegExpImpl::IrregexpResult result; | 
 | 3500 |   if (regexp->CaptureCount() == 0) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3501 |     result = SearchRegExpNoCaptureMultiple(isolate, | 
 | 3502 |                                            subject, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3503 |                                            regexp, | 
 | 3504 |                                            last_match_info, | 
 | 3505 |                                            &builder); | 
 | 3506 |   } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3507 |     result = SearchRegExpMultiple(isolate, | 
 | 3508 |                                   subject, | 
 | 3509 |                                   regexp, | 
 | 3510 |                                   last_match_info, | 
 | 3511 |                                   &builder); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3512 |   } | 
 | 3513 |   if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3514 |   if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3515 |   ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); | 
 | 3516 |   return Failure::Exception(); | 
 | 3517 | } | 
 | 3518 |  | 
 | 3519 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 3520 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3521 |   NoHandleAllocation ha; | 
 | 3522 |   ASSERT(args.length() == 2); | 
 | 3523 |  | 
 | 3524 |   // Fast case where the result is a one character string. | 
 | 3525 |   if (args[0]->IsSmi() && args[1]->IsSmi()) { | 
 | 3526 |     int value = Smi::cast(args[0])->value(); | 
 | 3527 |     int radix = Smi::cast(args[1])->value(); | 
 | 3528 |     if (value >= 0 && value < radix) { | 
 | 3529 |       RUNTIME_ASSERT(radix <= 36); | 
 | 3530 |       // Character array used for conversion. | 
 | 3531 |       static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz"; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3532 |       return isolate->heap()-> | 
 | 3533 |           LookupSingleCharacterStringFromCode(kCharTable[value]); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3534 |     } | 
 | 3535 |   } | 
 | 3536 |  | 
 | 3537 |   // Slow case. | 
 | 3538 |   CONVERT_DOUBLE_CHECKED(value, args[0]); | 
 | 3539 |   if (isnan(value)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3540 |     return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN")); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3541 |   } | 
 | 3542 |   if (isinf(value)) { | 
 | 3543 |     if (value < 0) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3544 |       return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity")); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3545 |     } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3546 |     return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity")); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3547 |   } | 
 | 3548 |   CONVERT_DOUBLE_CHECKED(radix_number, args[1]); | 
 | 3549 |   int radix = FastD2I(radix_number); | 
 | 3550 |   RUNTIME_ASSERT(2 <= radix && radix <= 36); | 
 | 3551 |   char* str = DoubleToRadixCString(value, radix); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3552 |   MaybeObject* result = | 
 | 3553 |       isolate->heap()->AllocateStringFromAscii(CStrVector(str)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3554 |   DeleteArray(str); | 
 | 3555 |   return result; | 
 | 3556 | } | 
 | 3557 |  | 
 | 3558 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 3559 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3560 |   NoHandleAllocation ha; | 
 | 3561 |   ASSERT(args.length() == 2); | 
 | 3562 |  | 
 | 3563 |   CONVERT_DOUBLE_CHECKED(value, args[0]); | 
 | 3564 |   if (isnan(value)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3565 |     return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN")); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3566 |   } | 
 | 3567 |   if (isinf(value)) { | 
 | 3568 |     if (value < 0) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3569 |       return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity")); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3570 |     } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3571 |     return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity")); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3572 |   } | 
 | 3573 |   CONVERT_DOUBLE_CHECKED(f_number, args[1]); | 
 | 3574 |   int f = FastD2I(f_number); | 
 | 3575 |   RUNTIME_ASSERT(f >= 0); | 
 | 3576 |   char* str = DoubleToFixedCString(value, f); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3577 |   MaybeObject* res = | 
 | 3578 |       isolate->heap()->AllocateStringFromAscii(CStrVector(str)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3579 |   DeleteArray(str); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3580 |   return res; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3581 | } | 
 | 3582 |  | 
 | 3583 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 3584 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3585 |   NoHandleAllocation ha; | 
 | 3586 |   ASSERT(args.length() == 2); | 
 | 3587 |  | 
 | 3588 |   CONVERT_DOUBLE_CHECKED(value, args[0]); | 
 | 3589 |   if (isnan(value)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3590 |     return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN")); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3591 |   } | 
 | 3592 |   if (isinf(value)) { | 
 | 3593 |     if (value < 0) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3594 |       return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity")); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3595 |     } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3596 |     return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity")); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3597 |   } | 
 | 3598 |   CONVERT_DOUBLE_CHECKED(f_number, args[1]); | 
 | 3599 |   int f = FastD2I(f_number); | 
 | 3600 |   RUNTIME_ASSERT(f >= -1 && f <= 20); | 
 | 3601 |   char* str = DoubleToExponentialCString(value, f); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3602 |   MaybeObject* res = | 
 | 3603 |       isolate->heap()->AllocateStringFromAscii(CStrVector(str)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3604 |   DeleteArray(str); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3605 |   return res; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3606 | } | 
 | 3607 |  | 
 | 3608 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 3609 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3610 |   NoHandleAllocation ha; | 
 | 3611 |   ASSERT(args.length() == 2); | 
 | 3612 |  | 
 | 3613 |   CONVERT_DOUBLE_CHECKED(value, args[0]); | 
 | 3614 |   if (isnan(value)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3615 |     return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN")); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3616 |   } | 
 | 3617 |   if (isinf(value)) { | 
 | 3618 |     if (value < 0) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3619 |       return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity")); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3620 |     } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3621 |     return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity")); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3622 |   } | 
 | 3623 |   CONVERT_DOUBLE_CHECKED(f_number, args[1]); | 
 | 3624 |   int f = FastD2I(f_number); | 
 | 3625 |   RUNTIME_ASSERT(f >= 1 && f <= 21); | 
 | 3626 |   char* str = DoubleToPrecisionCString(value, f); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3627 |   MaybeObject* res = | 
 | 3628 |       isolate->heap()->AllocateStringFromAscii(CStrVector(str)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3629 |   DeleteArray(str); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3630 |   return res; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3631 | } | 
 | 3632 |  | 
 | 3633 |  | 
 | 3634 | // Returns a single character string where first character equals | 
 | 3635 | // string->Get(index). | 
 | 3636 | static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { | 
 | 3637 |   if (index < static_cast<uint32_t>(string->length())) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3638 |     string->TryFlatten(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3639 |     return LookupSingleCharacterStringFromCode( | 
 | 3640 |         string->Get(index)); | 
 | 3641 |   } | 
 | 3642 |   return Execution::CharAt(string, index); | 
 | 3643 | } | 
 | 3644 |  | 
 | 3645 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3646 | MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate, | 
 | 3647 |                                          Handle<Object> object, | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 3648 |                                          uint32_t index) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3649 |   // Handle [] indexing on Strings | 
 | 3650 |   if (object->IsString()) { | 
 | 3651 |     Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); | 
 | 3652 |     if (!result->IsUndefined()) return *result; | 
 | 3653 |   } | 
 | 3654 |  | 
 | 3655 |   // Handle [] indexing on String objects | 
 | 3656 |   if (object->IsStringObjectWithCharacterAt(index)) { | 
 | 3657 |     Handle<JSValue> js_value = Handle<JSValue>::cast(object); | 
 | 3658 |     Handle<Object> result = | 
 | 3659 |         GetCharAt(Handle<String>(String::cast(js_value->value())), index); | 
 | 3660 |     if (!result->IsUndefined()) return *result; | 
 | 3661 |   } | 
 | 3662 |  | 
 | 3663 |   if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | 
 | 3664 |     Handle<Object> prototype = GetPrototype(object); | 
 | 3665 |     return prototype->GetElement(index); | 
 | 3666 |   } | 
 | 3667 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3668 |   return GetElement(object, index); | 
 | 3669 | } | 
 | 3670 |  | 
 | 3671 |  | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 3672 | MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3673 |   return object->GetElement(index); | 
 | 3674 | } | 
 | 3675 |  | 
 | 3676 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3677 | MaybeObject* Runtime::GetObjectProperty(Isolate* isolate, | 
 | 3678 |                                         Handle<Object> object, | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 3679 |                                         Handle<Object> key) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3680 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3681 |  | 
 | 3682 |   if (object->IsUndefined() || object->IsNull()) { | 
 | 3683 |     Handle<Object> args[2] = { key, object }; | 
 | 3684 |     Handle<Object> error = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3685 |         isolate->factory()->NewTypeError("non_object_property_load", | 
 | 3686 |                                          HandleVector(args, 2)); | 
 | 3687 |     return isolate->Throw(*error); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3688 |   } | 
 | 3689 |  | 
 | 3690 |   // Check if the given key is an array index. | 
 | 3691 |   uint32_t index; | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 3692 |   if (key->ToArrayIndex(&index)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3693 |     return GetElementOrCharAt(isolate, object, index); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3694 |   } | 
 | 3695 |  | 
 | 3696 |   // Convert the key to a string - possibly by calling back into JavaScript. | 
 | 3697 |   Handle<String> name; | 
 | 3698 |   if (key->IsString()) { | 
 | 3699 |     name = Handle<String>::cast(key); | 
 | 3700 |   } else { | 
 | 3701 |     bool has_pending_exception = false; | 
 | 3702 |     Handle<Object> converted = | 
 | 3703 |         Execution::ToString(key, &has_pending_exception); | 
 | 3704 |     if (has_pending_exception) return Failure::Exception(); | 
 | 3705 |     name = Handle<String>::cast(converted); | 
 | 3706 |   } | 
 | 3707 |  | 
 | 3708 |   // Check if the name is trivially convertible to an index and get | 
 | 3709 |   // the element if so. | 
 | 3710 |   if (name->AsArrayIndex(&index)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3711 |     return GetElementOrCharAt(isolate, object, index); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3712 |   } else { | 
 | 3713 |     PropertyAttributes attr; | 
 | 3714 |     return object->GetProperty(*name, &attr); | 
 | 3715 |   } | 
 | 3716 | } | 
 | 3717 |  | 
 | 3718 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 3719 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3720 |   NoHandleAllocation ha; | 
 | 3721 |   ASSERT(args.length() == 2); | 
 | 3722 |  | 
 | 3723 |   Handle<Object> object = args.at<Object>(0); | 
 | 3724 |   Handle<Object> key = args.at<Object>(1); | 
 | 3725 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3726 |   return Runtime::GetObjectProperty(isolate, object, key); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3727 | } | 
 | 3728 |  | 
 | 3729 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3730 | // KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 3731 | RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3732 |   NoHandleAllocation ha; | 
 | 3733 |   ASSERT(args.length() == 2); | 
 | 3734 |  | 
 | 3735 |   // Fast cases for getting named properties of the receiver JSObject | 
 | 3736 |   // itself. | 
 | 3737 |   // | 
 | 3738 |   // The global proxy objects has to be excluded since LocalLookup on | 
 | 3739 |   // the global proxy object can return a valid result even though the | 
 | 3740 |   // global proxy object never has properties.  This is the case | 
 | 3741 |   // because the global proxy object forwards everything to its hidden | 
 | 3742 |   // prototype including local lookups. | 
 | 3743 |   // | 
 | 3744 |   // Additionally, we need to make sure that we do not cache results | 
 | 3745 |   // for objects that require access checks. | 
 | 3746 |   if (args[0]->IsJSObject() && | 
 | 3747 |       !args[0]->IsJSGlobalProxy() && | 
 | 3748 |       !args[0]->IsAccessCheckNeeded() && | 
 | 3749 |       args[1]->IsString()) { | 
 | 3750 |     JSObject* receiver = JSObject::cast(args[0]); | 
 | 3751 |     String* key = String::cast(args[1]); | 
 | 3752 |     if (receiver->HasFastProperties()) { | 
 | 3753 |       // Attempt to use lookup cache. | 
 | 3754 |       Map* receiver_map = receiver->map(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3755 |       KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache(); | 
 | 3756 |       int offset = keyed_lookup_cache->Lookup(receiver_map, key); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3757 |       if (offset != -1) { | 
 | 3758 |         Object* value = receiver->FastPropertyAt(offset); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3759 |         return value->IsTheHole() ? isolate->heap()->undefined_value() : value; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3760 |       } | 
 | 3761 |       // Lookup cache miss.  Perform lookup and update the cache if appropriate. | 
 | 3762 |       LookupResult result; | 
 | 3763 |       receiver->LocalLookup(key, &result); | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 3764 |       if (result.IsProperty() && result.type() == FIELD) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3765 |         int offset = result.GetFieldIndex(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3766 |         keyed_lookup_cache->Update(receiver_map, key, offset); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3767 |         return receiver->FastPropertyAt(offset); | 
 | 3768 |       } | 
 | 3769 |     } else { | 
 | 3770 |       // Attempt dictionary lookup. | 
 | 3771 |       StringDictionary* dictionary = receiver->property_dictionary(); | 
 | 3772 |       int entry = dictionary->FindEntry(key); | 
 | 3773 |       if ((entry != StringDictionary::kNotFound) && | 
 | 3774 |           (dictionary->DetailsAt(entry).type() == NORMAL)) { | 
 | 3775 |         Object* value = dictionary->ValueAt(entry); | 
 | 3776 |         if (!receiver->IsGlobalObject()) return value; | 
 | 3777 |         value = JSGlobalPropertyCell::cast(value)->value(); | 
 | 3778 |         if (!value->IsTheHole()) return value; | 
 | 3779 |         // If value is the hole do the general lookup. | 
 | 3780 |       } | 
 | 3781 |     } | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 3782 |   } else if (args[0]->IsString() && args[1]->IsSmi()) { | 
 | 3783 |     // Fast case for string indexing using [] with a smi index. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3784 |     HandleScope scope(isolate); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 3785 |     Handle<String> str = args.at<String>(0); | 
 | 3786 |     int index = Smi::cast(args[1])->value(); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 3787 |     if (index >= 0 && index < str->length()) { | 
 | 3788 |       Handle<Object> result = GetCharAt(str, index); | 
 | 3789 |       return *result; | 
 | 3790 |     } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3791 |   } | 
 | 3792 |  | 
 | 3793 |   // Fall back to GetObjectProperty. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3794 |   return Runtime::GetObjectProperty(isolate, | 
 | 3795 |                                     args.at<Object>(0), | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3796 |                                     args.at<Object>(1)); | 
 | 3797 | } | 
 | 3798 |  | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 3799 | // Implements part of 8.12.9 DefineOwnProperty. | 
 | 3800 | // There are 3 cases that lead here: | 
 | 3801 | // Step 4b - define a new accessor property. | 
 | 3802 | // Steps 9c & 12 - replace an existing data property with an accessor property. | 
 | 3803 | // Step 12 - update an existing accessor property with an accessor or generic | 
 | 3804 | //           descriptor. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 3805 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) { | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 3806 |   ASSERT(args.length() == 5); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3807 |   HandleScope scope(isolate); | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 3808 |   CONVERT_ARG_CHECKED(JSObject, obj, 0); | 
 | 3809 |   CONVERT_CHECKED(String, name, args[1]); | 
 | 3810 |   CONVERT_CHECKED(Smi, flag_setter, args[2]); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 3811 |   Object* fun = args[3]; | 
 | 3812 |   RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined()); | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 3813 |   CONVERT_CHECKED(Smi, flag_attr, args[4]); | 
 | 3814 |   int unchecked = flag_attr->value(); | 
 | 3815 |   RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); | 
 | 3816 |   RUNTIME_ASSERT(!obj->IsNull()); | 
 | 3817 |   LookupResult result; | 
 | 3818 |   obj->LocalLookupRealNamedProperty(name, &result); | 
 | 3819 |  | 
 | 3820 |   PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); | 
 | 3821 |   // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION | 
 | 3822 |   // delete it to avoid running into trouble in DefineAccessor, which | 
 | 3823 |   // handles this incorrectly if the property is readonly (does nothing) | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 3824 |   if (result.IsProperty() && | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 3825 |       (result.type() == FIELD || result.type() == NORMAL | 
 | 3826 |        || result.type() == CONSTANT_FUNCTION)) { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 3827 |     Object* ok; | 
 | 3828 |     { MaybeObject* maybe_ok = | 
 | 3829 |           obj->DeleteProperty(name, JSObject::NORMAL_DELETION); | 
 | 3830 |       if (!maybe_ok->ToObject(&ok)) return maybe_ok; | 
 | 3831 |     } | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 3832 |   } | 
 | 3833 |   return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr); | 
 | 3834 | } | 
 | 3835 |  | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 3836 | // Implements part of 8.12.9 DefineOwnProperty. | 
 | 3837 | // There are 3 cases that lead here: | 
 | 3838 | // Step 4a - define a new data property. | 
 | 3839 | // Steps 9b & 12 - replace an existing accessor property with a data property. | 
 | 3840 | // Step 12 - update an existing data property with a data or generic | 
 | 3841 | //           descriptor. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 3842 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) { | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 3843 |   ASSERT(args.length() == 4); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3844 |   HandleScope scope(isolate); | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 3845 |   CONVERT_ARG_CHECKED(JSObject, js_object, 0); | 
 | 3846 |   CONVERT_ARG_CHECKED(String, name, 1); | 
 | 3847 |   Handle<Object> obj_value = args.at<Object>(2); | 
 | 3848 |  | 
 | 3849 |   CONVERT_CHECKED(Smi, flag, args[3]); | 
 | 3850 |   int unchecked = flag->value(); | 
 | 3851 |   RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); | 
 | 3852 |  | 
| Kristian Monsen | 9dcf7e2 | 2010-06-28 14:14:28 +0100 | [diff] [blame] | 3853 |   PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); | 
 | 3854 |  | 
 | 3855 |   // Check if this is an element. | 
 | 3856 |   uint32_t index; | 
 | 3857 |   bool is_element = name->AsArrayIndex(&index); | 
 | 3858 |  | 
 | 3859 |   // Special case for elements if any of the flags are true. | 
 | 3860 |   // If elements are in fast case we always implicitly assume that: | 
 | 3861 |   // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false. | 
 | 3862 |   if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) && | 
 | 3863 |       is_element) { | 
 | 3864 |     // Normalize the elements to enable attributes on the property. | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 3865 |     if (js_object->IsJSGlobalProxy()) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 3866 |       // We do not need to do access checks here since these has already | 
 | 3867 |       // been performed by the call to GetOwnProperty. | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 3868 |       Handle<Object> proto(js_object->GetPrototype()); | 
 | 3869 |       // If proxy is detached, ignore the assignment. Alternatively, | 
 | 3870 |       // we could throw an exception. | 
 | 3871 |       if (proto->IsNull()) return *obj_value; | 
 | 3872 |       js_object = Handle<JSObject>::cast(proto); | 
 | 3873 |     } | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 3874 |     NormalizeElements(js_object); | 
 | 3875 |     Handle<NumberDictionary> dictionary(js_object->element_dictionary()); | 
| Kristian Monsen | 9dcf7e2 | 2010-06-28 14:14:28 +0100 | [diff] [blame] | 3876 |     // Make sure that we never go back to fast case. | 
 | 3877 |     dictionary->set_requires_slow_elements(); | 
 | 3878 |     PropertyDetails details = PropertyDetails(attr, NORMAL); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 3879 |     NumberDictionarySet(dictionary, index, obj_value, details); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 3880 |     return *obj_value; | 
| Kristian Monsen | 9dcf7e2 | 2010-06-28 14:14:28 +0100 | [diff] [blame] | 3881 |   } | 
 | 3882 |  | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 3883 |   LookupResult result; | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 3884 |   js_object->LookupRealNamedProperty(*name, &result); | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 3885 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3886 |   // To be compatible with safari we do not change the value on API objects | 
 | 3887 |   // in defineProperty. Firefox disagrees here, and actually changes the value. | 
 | 3888 |   if (result.IsProperty() && | 
 | 3889 |       (result.type() == CALLBACKS) && | 
 | 3890 |       result.GetCallbackObject()->IsAccessorInfo()) { | 
 | 3891 |     return isolate->heap()->undefined_value(); | 
 | 3892 |   } | 
 | 3893 |  | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 3894 |   // Take special care when attributes are different and there is already | 
 | 3895 |   // a property. For simplicity we normalize the property which enables us | 
 | 3896 |   // to not worry about changing the instance_descriptor and creating a new | 
 | 3897 |   // map. The current version of SetObjectProperty does not handle attributes | 
 | 3898 |   // correctly in the case where a property is a field and is reset with | 
 | 3899 |   // new attributes. | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 3900 |   if (result.IsProperty() && | 
 | 3901 |       (attr != result.GetAttributes() || result.type() == CALLBACKS)) { | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 3902 |     // New attributes - normalize to avoid writing to instance descriptor | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 3903 |     if (js_object->IsJSGlobalProxy()) { | 
 | 3904 |       // Since the result is a property, the prototype will exist so | 
 | 3905 |       // we don't have to check for null. | 
 | 3906 |       js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype())); | 
 | 3907 |     } | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 3908 |     NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0); | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 3909 |     // Use IgnoreAttributes version since a readonly property may be | 
 | 3910 |     // overridden and SetProperty does not allow this. | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 3911 |     return js_object->SetLocalPropertyIgnoreAttributes(*name, | 
 | 3912 |                                                        *obj_value, | 
 | 3913 |                                                        attr); | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 3914 |   } | 
| Kristian Monsen | 9dcf7e2 | 2010-06-28 14:14:28 +0100 | [diff] [blame] | 3915 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3916 |   return Runtime::ForceSetObjectProperty(isolate, | 
 | 3917 |                                          js_object, | 
 | 3918 |                                          name, | 
 | 3919 |                                          obj_value, | 
 | 3920 |                                          attr); | 
| Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 3921 | } | 
 | 3922 |  | 
 | 3923 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3924 | MaybeObject* Runtime::SetObjectProperty(Isolate* isolate, | 
 | 3925 |                                         Handle<Object> object, | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 3926 |                                         Handle<Object> key, | 
 | 3927 |                                         Handle<Object> value, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 3928 |                                         PropertyAttributes attr, | 
 | 3929 |                                         StrictModeFlag strict_mode) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3930 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3931 |  | 
 | 3932 |   if (object->IsUndefined() || object->IsNull()) { | 
 | 3933 |     Handle<Object> args[2] = { key, object }; | 
 | 3934 |     Handle<Object> error = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3935 |         isolate->factory()->NewTypeError("non_object_property_store", | 
 | 3936 |                                          HandleVector(args, 2)); | 
 | 3937 |     return isolate->Throw(*error); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3938 |   } | 
 | 3939 |  | 
 | 3940 |   // If the object isn't a JavaScript object, we ignore the store. | 
 | 3941 |   if (!object->IsJSObject()) return *value; | 
 | 3942 |  | 
 | 3943 |   Handle<JSObject> js_object = Handle<JSObject>::cast(object); | 
 | 3944 |  | 
 | 3945 |   // Check if the given key is an array index. | 
 | 3946 |   uint32_t index; | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 3947 |   if (key->ToArrayIndex(&index)) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3948 |     // In Firefox/SpiderMonkey, Safari and Opera you can access the characters | 
 | 3949 |     // of a string using [] notation.  We need to support this too in | 
 | 3950 |     // JavaScript. | 
 | 3951 |     // In the case of a String object we just need to redirect the assignment to | 
 | 3952 |     // the underlying string if the index is in range.  Since the underlying | 
 | 3953 |     // string does nothing with the assignment then we can ignore such | 
 | 3954 |     // assignments. | 
 | 3955 |     if (js_object->IsStringObjectWithCharacterAt(index)) { | 
 | 3956 |       return *value; | 
 | 3957 |     } | 
 | 3958 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 3959 |     Handle<Object> result = SetElement(js_object, index, value, strict_mode); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3960 |     if (result.is_null()) return Failure::Exception(); | 
 | 3961 |     return *value; | 
 | 3962 |   } | 
 | 3963 |  | 
 | 3964 |   if (key->IsString()) { | 
 | 3965 |     Handle<Object> result; | 
 | 3966 |     if (Handle<String>::cast(key)->AsArrayIndex(&index)) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 3967 |       result = SetElement(js_object, index, value, strict_mode); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3968 |     } else { | 
 | 3969 |       Handle<String> key_string = Handle<String>::cast(key); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 3970 |       key_string->TryFlatten(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 3971 |       result = SetProperty(js_object, key_string, value, attr, strict_mode); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3972 |     } | 
 | 3973 |     if (result.is_null()) return Failure::Exception(); | 
 | 3974 |     return *value; | 
 | 3975 |   } | 
 | 3976 |  | 
 | 3977 |   // Call-back into JavaScript to convert the key to a string. | 
 | 3978 |   bool has_pending_exception = false; | 
 | 3979 |   Handle<Object> converted = Execution::ToString(key, &has_pending_exception); | 
 | 3980 |   if (has_pending_exception) return Failure::Exception(); | 
 | 3981 |   Handle<String> name = Handle<String>::cast(converted); | 
 | 3982 |  | 
 | 3983 |   if (name->AsArrayIndex(&index)) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 3984 |     return js_object->SetElement(index, *value, strict_mode); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3985 |   } else { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 3986 |     return js_object->SetProperty(*name, *value, attr, strict_mode); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3987 |   } | 
 | 3988 | } | 
 | 3989 |  | 
 | 3990 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3991 | MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate, | 
 | 3992 |                                              Handle<JSObject> js_object, | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 3993 |                                              Handle<Object> key, | 
 | 3994 |                                              Handle<Object> value, | 
 | 3995 |                                              PropertyAttributes attr) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 3996 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 3997 |  | 
 | 3998 |   // Check if the given key is an array index. | 
 | 3999 |   uint32_t index; | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 4000 |   if (key->ToArrayIndex(&index)) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4001 |     // In Firefox/SpiderMonkey, Safari and Opera you can access the characters | 
 | 4002 |     // of a string using [] notation.  We need to support this too in | 
 | 4003 |     // JavaScript. | 
 | 4004 |     // In the case of a String object we just need to redirect the assignment to | 
 | 4005 |     // the underlying string if the index is in range.  Since the underlying | 
 | 4006 |     // string does nothing with the assignment then we can ignore such | 
 | 4007 |     // assignments. | 
 | 4008 |     if (js_object->IsStringObjectWithCharacterAt(index)) { | 
 | 4009 |       return *value; | 
 | 4010 |     } | 
 | 4011 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 4012 |     return js_object->SetElement(index, *value, kNonStrictMode); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4013 |   } | 
 | 4014 |  | 
 | 4015 |   if (key->IsString()) { | 
 | 4016 |     if (Handle<String>::cast(key)->AsArrayIndex(&index)) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 4017 |       return js_object->SetElement(index, *value, kNonStrictMode); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4018 |     } else { | 
 | 4019 |       Handle<String> key_string = Handle<String>::cast(key); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 4020 |       key_string->TryFlatten(); | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 4021 |       return js_object->SetLocalPropertyIgnoreAttributes(*key_string, | 
 | 4022 |                                                          *value, | 
 | 4023 |                                                          attr); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4024 |     } | 
 | 4025 |   } | 
 | 4026 |  | 
 | 4027 |   // Call-back into JavaScript to convert the key to a string. | 
 | 4028 |   bool has_pending_exception = false; | 
 | 4029 |   Handle<Object> converted = Execution::ToString(key, &has_pending_exception); | 
 | 4030 |   if (has_pending_exception) return Failure::Exception(); | 
 | 4031 |   Handle<String> name = Handle<String>::cast(converted); | 
 | 4032 |  | 
 | 4033 |   if (name->AsArrayIndex(&index)) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 4034 |     return js_object->SetElement(index, *value, kNonStrictMode); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4035 |   } else { | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 4036 |     return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4037 |   } | 
 | 4038 | } | 
 | 4039 |  | 
 | 4040 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4041 | MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate, | 
 | 4042 |                                                 Handle<JSObject> js_object, | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 4043 |                                                 Handle<Object> key) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4044 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4045 |  | 
 | 4046 |   // Check if the given key is an array index. | 
 | 4047 |   uint32_t index; | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 4048 |   if (key->ToArrayIndex(&index)) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4049 |     // In Firefox/SpiderMonkey, Safari and Opera you can access the | 
 | 4050 |     // characters of a string using [] notation.  In the case of a | 
 | 4051 |     // String object we just need to redirect the deletion to the | 
 | 4052 |     // underlying string if the index is in range.  Since the | 
 | 4053 |     // underlying string does nothing with the deletion, we can ignore | 
 | 4054 |     // such deletions. | 
 | 4055 |     if (js_object->IsStringObjectWithCharacterAt(index)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4056 |       return isolate->heap()->true_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4057 |     } | 
 | 4058 |  | 
 | 4059 |     return js_object->DeleteElement(index, JSObject::FORCE_DELETION); | 
 | 4060 |   } | 
 | 4061 |  | 
 | 4062 |   Handle<String> key_string; | 
 | 4063 |   if (key->IsString()) { | 
 | 4064 |     key_string = Handle<String>::cast(key); | 
 | 4065 |   } else { | 
 | 4066 |     // Call-back into JavaScript to convert the key to a string. | 
 | 4067 |     bool has_pending_exception = false; | 
 | 4068 |     Handle<Object> converted = Execution::ToString(key, &has_pending_exception); | 
 | 4069 |     if (has_pending_exception) return Failure::Exception(); | 
 | 4070 |     key_string = Handle<String>::cast(converted); | 
 | 4071 |   } | 
 | 4072 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 4073 |   key_string->TryFlatten(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4074 |   return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION); | 
 | 4075 | } | 
 | 4076 |  | 
 | 4077 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4078 | RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4079 |   NoHandleAllocation ha; | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 4080 |   RUNTIME_ASSERT(args.length() == 4 || args.length() == 5); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4081 |  | 
 | 4082 |   Handle<Object> object = args.at<Object>(0); | 
 | 4083 |   Handle<Object> key = args.at<Object>(1); | 
 | 4084 |   Handle<Object> value = args.at<Object>(2); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 4085 |   CONVERT_SMI_CHECKED(unchecked_attributes, args[3]); | 
 | 4086 |   RUNTIME_ASSERT( | 
 | 4087 |       (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4088 |   // Compute attributes. | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 4089 |   PropertyAttributes attributes = | 
 | 4090 |       static_cast<PropertyAttributes>(unchecked_attributes); | 
 | 4091 |  | 
 | 4092 |   StrictModeFlag strict_mode = kNonStrictMode; | 
 | 4093 |   if (args.length() == 5) { | 
 | 4094 |     CONVERT_SMI_CHECKED(strict_unchecked, args[4]); | 
 | 4095 |     RUNTIME_ASSERT(strict_unchecked == kStrictMode || | 
 | 4096 |                    strict_unchecked == kNonStrictMode); | 
 | 4097 |     strict_mode = static_cast<StrictModeFlag>(strict_unchecked); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4098 |   } | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 4099 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4100 |   return Runtime::SetObjectProperty(isolate, | 
 | 4101 |                                     object, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 4102 |                                     key, | 
 | 4103 |                                     value, | 
 | 4104 |                                     attributes, | 
 | 4105 |                                     strict_mode); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4106 | } | 
 | 4107 |  | 
 | 4108 |  | 
 | 4109 | // Set a local property, even if it is READ_ONLY.  If the property does not | 
 | 4110 | // exist, it will be added with attributes NONE. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4111 | RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4112 |   NoHandleAllocation ha; | 
 | 4113 |   RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); | 
 | 4114 |   CONVERT_CHECKED(JSObject, object, args[0]); | 
 | 4115 |   CONVERT_CHECKED(String, name, args[1]); | 
 | 4116 |   // Compute attributes. | 
 | 4117 |   PropertyAttributes attributes = NONE; | 
 | 4118 |   if (args.length() == 4) { | 
 | 4119 |     CONVERT_CHECKED(Smi, value_obj, args[3]); | 
 | 4120 |     int unchecked_value = value_obj->value(); | 
 | 4121 |     // Only attribute bits should be set. | 
 | 4122 |     RUNTIME_ASSERT( | 
 | 4123 |         (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); | 
 | 4124 |     attributes = static_cast<PropertyAttributes>(unchecked_value); | 
 | 4125 |   } | 
 | 4126 |  | 
 | 4127 |   return object-> | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 4128 |       SetLocalPropertyIgnoreAttributes(name, args[2], attributes); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4129 | } | 
 | 4130 |  | 
 | 4131 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4132 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4133 |   NoHandleAllocation ha; | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 4134 |   ASSERT(args.length() == 3); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4135 |  | 
 | 4136 |   CONVERT_CHECKED(JSObject, object, args[0]); | 
 | 4137 |   CONVERT_CHECKED(String, key, args[1]); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 4138 |   CONVERT_SMI_CHECKED(strict, args[2]); | 
 | 4139 |   return object->DeleteProperty(key, (strict == kStrictMode) | 
 | 4140 |                                       ? JSObject::STRICT_DELETION | 
 | 4141 |                                       : JSObject::NORMAL_DELETION); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4142 | } | 
 | 4143 |  | 
 | 4144 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4145 | static Object* HasLocalPropertyImplementation(Isolate* isolate, | 
 | 4146 |                                               Handle<JSObject> object, | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4147 |                                               Handle<String> key) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4148 |   if (object->HasLocalProperty(*key)) return isolate->heap()->true_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4149 |   // Handle hidden prototypes.  If there's a hidden prototype above this thing | 
 | 4150 |   // then we have to check it for properties, because they are supposed to | 
 | 4151 |   // look like they are on this object. | 
 | 4152 |   Handle<Object> proto(object->GetPrototype()); | 
 | 4153 |   if (proto->IsJSObject() && | 
 | 4154 |       Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4155 |     return HasLocalPropertyImplementation(isolate, | 
 | 4156 |                                           Handle<JSObject>::cast(proto), | 
 | 4157 |                                           key); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4158 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4159 |   return isolate->heap()->false_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4160 | } | 
 | 4161 |  | 
 | 4162 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4163 | RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4164 |   NoHandleAllocation ha; | 
 | 4165 |   ASSERT(args.length() == 2); | 
 | 4166 |   CONVERT_CHECKED(String, key, args[1]); | 
 | 4167 |  | 
 | 4168 |   Object* obj = args[0]; | 
 | 4169 |   // Only JS objects can have properties. | 
 | 4170 |   if (obj->IsJSObject()) { | 
 | 4171 |     JSObject* object = JSObject::cast(obj); | 
 | 4172 |     // Fast case - no interceptors. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4173 |     if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4174 |     // Slow case.  Either it's not there or we have an interceptor.  We should | 
 | 4175 |     // have handles for this kind of deal. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4176 |     HandleScope scope(isolate); | 
 | 4177 |     return HasLocalPropertyImplementation(isolate, | 
 | 4178 |                                           Handle<JSObject>(object), | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4179 |                                           Handle<String>(key)); | 
 | 4180 |   } else if (obj->IsString()) { | 
 | 4181 |     // Well, there is one exception:  Handle [] on strings. | 
 | 4182 |     uint32_t index; | 
 | 4183 |     if (key->AsArrayIndex(&index)) { | 
 | 4184 |       String* string = String::cast(obj); | 
 | 4185 |       if (index < static_cast<uint32_t>(string->length())) | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4186 |         return isolate->heap()->true_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4187 |     } | 
 | 4188 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4189 |   return isolate->heap()->false_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4190 | } | 
 | 4191 |  | 
 | 4192 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4193 | RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4194 |   NoHandleAllocation na; | 
 | 4195 |   ASSERT(args.length() == 2); | 
 | 4196 |  | 
 | 4197 |   // Only JS objects can have properties. | 
 | 4198 |   if (args[0]->IsJSObject()) { | 
 | 4199 |     JSObject* object = JSObject::cast(args[0]); | 
 | 4200 |     CONVERT_CHECKED(String, key, args[1]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4201 |     if (object->HasProperty(key)) return isolate->heap()->true_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4202 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4203 |   return isolate->heap()->false_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4204 | } | 
 | 4205 |  | 
 | 4206 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4207 | RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4208 |   NoHandleAllocation na; | 
 | 4209 |   ASSERT(args.length() == 2); | 
 | 4210 |  | 
 | 4211 |   // Only JS objects can have elements. | 
 | 4212 |   if (args[0]->IsJSObject()) { | 
 | 4213 |     JSObject* object = JSObject::cast(args[0]); | 
 | 4214 |     CONVERT_CHECKED(Smi, index_obj, args[1]); | 
 | 4215 |     uint32_t index = index_obj->value(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4216 |     if (object->HasElement(index)) return isolate->heap()->true_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4217 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4218 |   return isolate->heap()->false_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4219 | } | 
 | 4220 |  | 
 | 4221 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4222 | RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4223 |   NoHandleAllocation ha; | 
 | 4224 |   ASSERT(args.length() == 2); | 
 | 4225 |  | 
 | 4226 |   CONVERT_CHECKED(JSObject, object, args[0]); | 
 | 4227 |   CONVERT_CHECKED(String, key, args[1]); | 
 | 4228 |  | 
 | 4229 |   uint32_t index; | 
 | 4230 |   if (key->AsArrayIndex(&index)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4231 |     return isolate->heap()->ToBoolean(object->HasElement(index)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4232 |   } | 
 | 4233 |  | 
 | 4234 |   PropertyAttributes att = object->GetLocalPropertyAttribute(key); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4235 |   return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4236 | } | 
 | 4237 |  | 
 | 4238 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4239 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4240 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4241 |   ASSERT(args.length() == 1); | 
 | 4242 |   CONVERT_ARG_CHECKED(JSObject, object, 0); | 
 | 4243 |   return *GetKeysFor(object); | 
 | 4244 | } | 
 | 4245 |  | 
 | 4246 |  | 
 | 4247 | // Returns either a FixedArray as Runtime_GetPropertyNames, | 
 | 4248 | // or, if the given object has an enum cache that contains | 
 | 4249 | // all enumerable properties of the object and its prototypes | 
 | 4250 | // have none, the map of the object. This is used to speed up | 
 | 4251 | // the check for deletions during a for-in. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4252 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4253 |   ASSERT(args.length() == 1); | 
 | 4254 |  | 
 | 4255 |   CONVERT_CHECKED(JSObject, raw_object, args[0]); | 
 | 4256 |  | 
 | 4257 |   if (raw_object->IsSimpleEnum()) return raw_object->map(); | 
 | 4258 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4259 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4260 |   Handle<JSObject> object(raw_object); | 
 | 4261 |   Handle<FixedArray> content = GetKeysInFixedArrayFor(object, | 
 | 4262 |                                                       INCLUDE_PROTOS); | 
 | 4263 |  | 
 | 4264 |   // Test again, since cache may have been built by preceding call. | 
 | 4265 |   if (object->IsSimpleEnum()) return object->map(); | 
 | 4266 |  | 
 | 4267 |   return *content; | 
 | 4268 | } | 
 | 4269 |  | 
 | 4270 |  | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4271 | // Find the length of the prototype chain that is to to handled as one. If a | 
 | 4272 | // prototype object is hidden it is to be viewed as part of the the object it | 
 | 4273 | // is prototype for. | 
 | 4274 | static int LocalPrototypeChainLength(JSObject* obj) { | 
 | 4275 |   int count = 1; | 
 | 4276 |   Object* proto = obj->GetPrototype(); | 
 | 4277 |   while (proto->IsJSObject() && | 
 | 4278 |          JSObject::cast(proto)->map()->is_hidden_prototype()) { | 
 | 4279 |     count++; | 
 | 4280 |     proto = JSObject::cast(proto)->GetPrototype(); | 
 | 4281 |   } | 
 | 4282 |   return count; | 
 | 4283 | } | 
 | 4284 |  | 
 | 4285 |  | 
 | 4286 | // Return the names of the local named properties. | 
 | 4287 | // args[0]: object | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4288 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4289 |   HandleScope scope(isolate); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4290 |   ASSERT(args.length() == 1); | 
 | 4291 |   if (!args[0]->IsJSObject()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4292 |     return isolate->heap()->undefined_value(); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4293 |   } | 
 | 4294 |   CONVERT_ARG_CHECKED(JSObject, obj, 0); | 
 | 4295 |  | 
 | 4296 |   // Skip the global proxy as it has no properties and always delegates to the | 
 | 4297 |   // real global object. | 
 | 4298 |   if (obj->IsJSGlobalProxy()) { | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 4299 |     // Only collect names if access is permitted. | 
 | 4300 |     if (obj->IsAccessCheckNeeded() && | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4301 |         !isolate->MayNamedAccess(*obj, | 
 | 4302 |                                  isolate->heap()->undefined_value(), | 
 | 4303 |                                  v8::ACCESS_KEYS)) { | 
 | 4304 |       isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS); | 
 | 4305 |       return *isolate->factory()->NewJSArray(0); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 4306 |     } | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4307 |     obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype())); | 
 | 4308 |   } | 
 | 4309 |  | 
 | 4310 |   // Find the number of objects making up this. | 
 | 4311 |   int length = LocalPrototypeChainLength(*obj); | 
 | 4312 |  | 
 | 4313 |   // Find the number of local properties for each of the objects. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 4314 |   ScopedVector<int> local_property_count(length); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4315 |   int total_property_count = 0; | 
 | 4316 |   Handle<JSObject> jsproto = obj; | 
 | 4317 |   for (int i = 0; i < length; i++) { | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 4318 |     // Only collect names if access is permitted. | 
 | 4319 |     if (jsproto->IsAccessCheckNeeded() && | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4320 |         !isolate->MayNamedAccess(*jsproto, | 
 | 4321 |                                  isolate->heap()->undefined_value(), | 
 | 4322 |                                  v8::ACCESS_KEYS)) { | 
 | 4323 |       isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS); | 
 | 4324 |       return *isolate->factory()->NewJSArray(0); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 4325 |     } | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4326 |     int n; | 
 | 4327 |     n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE)); | 
 | 4328 |     local_property_count[i] = n; | 
 | 4329 |     total_property_count += n; | 
 | 4330 |     if (i < length - 1) { | 
 | 4331 |       jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); | 
 | 4332 |     } | 
 | 4333 |   } | 
 | 4334 |  | 
 | 4335 |   // Allocate an array with storage for all the property names. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4336 |   Handle<FixedArray> names = | 
 | 4337 |       isolate->factory()->NewFixedArray(total_property_count); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4338 |  | 
 | 4339 |   // Get the property names. | 
 | 4340 |   jsproto = obj; | 
 | 4341 |   int proto_with_hidden_properties = 0; | 
| Ben Murdoch | 6d7cb00 | 2011-08-04 19:25:22 +0100 | [diff] [blame] | 4342 |   int next_copy_index = 0; | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4343 |   for (int i = 0; i < length; i++) { | 
| Ben Murdoch | 6d7cb00 | 2011-08-04 19:25:22 +0100 | [diff] [blame] | 4344 |     jsproto->GetLocalPropertyNames(*names, next_copy_index); | 
 | 4345 |     next_copy_index += local_property_count[i]; | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4346 |     if (!GetHiddenProperties(jsproto, false)->IsUndefined()) { | 
 | 4347 |       proto_with_hidden_properties++; | 
 | 4348 |     } | 
 | 4349 |     if (i < length - 1) { | 
 | 4350 |       jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); | 
 | 4351 |     } | 
 | 4352 |   } | 
 | 4353 |  | 
 | 4354 |   // Filter out name of hidden propeties object. | 
 | 4355 |   if (proto_with_hidden_properties > 0) { | 
 | 4356 |     Handle<FixedArray> old_names = names; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4357 |     names = isolate->factory()->NewFixedArray( | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4358 |         names->length() - proto_with_hidden_properties); | 
 | 4359 |     int dest_pos = 0; | 
 | 4360 |     for (int i = 0; i < total_property_count; i++) { | 
 | 4361 |       Object* name = old_names->get(i); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4362 |       if (name == isolate->heap()->hidden_symbol()) { | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4363 |         continue; | 
 | 4364 |       } | 
 | 4365 |       names->set(dest_pos++, name); | 
 | 4366 |     } | 
 | 4367 |   } | 
 | 4368 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4369 |   return *isolate->factory()->NewJSArrayWithElements(names); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4370 | } | 
 | 4371 |  | 
 | 4372 |  | 
 | 4373 | // Return the names of the local indexed properties. | 
 | 4374 | // args[0]: object | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4375 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4376 |   HandleScope scope(isolate); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4377 |   ASSERT(args.length() == 1); | 
 | 4378 |   if (!args[0]->IsJSObject()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4379 |     return isolate->heap()->undefined_value(); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4380 |   } | 
 | 4381 |   CONVERT_ARG_CHECKED(JSObject, obj, 0); | 
 | 4382 |  | 
 | 4383 |   int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE)); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4384 |   Handle<FixedArray> names = isolate->factory()->NewFixedArray(n); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4385 |   obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE)); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4386 |   return *isolate->factory()->NewJSArrayWithElements(names); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4387 | } | 
 | 4388 |  | 
 | 4389 |  | 
 | 4390 | // Return information on whether an object has a named or indexed interceptor. | 
 | 4391 | // args[0]: object | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4392 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4393 |   HandleScope scope(isolate); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4394 |   ASSERT(args.length() == 1); | 
 | 4395 |   if (!args[0]->IsJSObject()) { | 
 | 4396 |     return Smi::FromInt(0); | 
 | 4397 |   } | 
 | 4398 |   CONVERT_ARG_CHECKED(JSObject, obj, 0); | 
 | 4399 |  | 
 | 4400 |   int result = 0; | 
 | 4401 |   if (obj->HasNamedInterceptor()) result |= 2; | 
 | 4402 |   if (obj->HasIndexedInterceptor()) result |= 1; | 
 | 4403 |  | 
 | 4404 |   return Smi::FromInt(result); | 
 | 4405 | } | 
 | 4406 |  | 
 | 4407 |  | 
 | 4408 | // Return property names from named interceptor. | 
 | 4409 | // args[0]: object | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4410 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4411 |   HandleScope scope(isolate); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4412 |   ASSERT(args.length() == 1); | 
 | 4413 |   CONVERT_ARG_CHECKED(JSObject, obj, 0); | 
 | 4414 |  | 
 | 4415 |   if (obj->HasNamedInterceptor()) { | 
 | 4416 |     v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj); | 
 | 4417 |     if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); | 
 | 4418 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4419 |   return isolate->heap()->undefined_value(); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4420 | } | 
 | 4421 |  | 
 | 4422 |  | 
 | 4423 | // Return element names from indexed interceptor. | 
 | 4424 | // args[0]: object | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4425 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4426 |   HandleScope scope(isolate); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4427 |   ASSERT(args.length() == 1); | 
 | 4428 |   CONVERT_ARG_CHECKED(JSObject, obj, 0); | 
 | 4429 |  | 
 | 4430 |   if (obj->HasIndexedInterceptor()) { | 
 | 4431 |     v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj); | 
 | 4432 |     if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); | 
 | 4433 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4434 |   return isolate->heap()->undefined_value(); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4435 | } | 
 | 4436 |  | 
 | 4437 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4438 | RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4439 |   ASSERT_EQ(args.length(), 1); | 
 | 4440 |   CONVERT_CHECKED(JSObject, raw_object, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4441 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4442 |   Handle<JSObject> object(raw_object); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 4443 |  | 
 | 4444 |   if (object->IsJSGlobalProxy()) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 4445 |     // Do access checks before going to the global object. | 
 | 4446 |     if (object->IsAccessCheckNeeded() && | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4447 |         !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(), | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 4448 |                              v8::ACCESS_KEYS)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4449 |       isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS); | 
 | 4450 |       return *isolate->factory()->NewJSArray(0); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 4451 |     } | 
 | 4452 |  | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 4453 |     Handle<Object> proto(object->GetPrototype()); | 
 | 4454 |     // If proxy is detached we simply return an empty array. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4455 |     if (proto->IsNull()) return *isolate->factory()->NewJSArray(0); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 4456 |     object = Handle<JSObject>::cast(proto); | 
 | 4457 |   } | 
 | 4458 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4459 |   Handle<FixedArray> contents = GetKeysInFixedArrayFor(object, | 
 | 4460 |                                                        LOCAL_ONLY); | 
 | 4461 |   // Some fast paths through GetKeysInFixedArrayFor reuse a cached | 
 | 4462 |   // property array and since the result is mutable we have to create | 
 | 4463 |   // a fresh clone on each invocation. | 
 | 4464 |   int length = contents->length(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4465 |   Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4466 |   for (int i = 0; i < length; i++) { | 
 | 4467 |     Object* entry = contents->get(i); | 
 | 4468 |     if (entry->IsString()) { | 
 | 4469 |       copy->set(i, entry); | 
 | 4470 |     } else { | 
 | 4471 |       ASSERT(entry->IsNumber()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4472 |       HandleScope scope(isolate); | 
 | 4473 |       Handle<Object> entry_handle(entry, isolate); | 
 | 4474 |       Handle<Object> entry_str = | 
 | 4475 |           isolate->factory()->NumberToString(entry_handle); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4476 |       copy->set(i, *entry_str); | 
 | 4477 |     } | 
 | 4478 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4479 |   return *isolate->factory()->NewJSArrayWithElements(copy); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4480 | } | 
 | 4481 |  | 
 | 4482 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4483 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4484 |   NoHandleAllocation ha; | 
 | 4485 |   ASSERT(args.length() == 1); | 
 | 4486 |  | 
 | 4487 |   // Compute the frame holding the arguments. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4488 |   JavaScriptFrameIterator it(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4489 |   it.AdvanceToArgumentsFrame(); | 
 | 4490 |   JavaScriptFrame* frame = it.frame(); | 
 | 4491 |  | 
 | 4492 |   // Get the actual number of provided arguments. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4493 |   const uint32_t n = frame->ComputeParametersCount(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4494 |  | 
 | 4495 |   // Try to convert the key to an index. If successful and within | 
 | 4496 |   // index return the the argument from the frame. | 
 | 4497 |   uint32_t index; | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 4498 |   if (args[0]->ToArrayIndex(&index) && index < n) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4499 |     return frame->GetParameter(index); | 
 | 4500 |   } | 
 | 4501 |  | 
 | 4502 |   // Convert the key to a string. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4503 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4504 |   bool exception = false; | 
 | 4505 |   Handle<Object> converted = | 
 | 4506 |       Execution::ToString(args.at<Object>(0), &exception); | 
 | 4507 |   if (exception) return Failure::Exception(); | 
 | 4508 |   Handle<String> key = Handle<String>::cast(converted); | 
 | 4509 |  | 
 | 4510 |   // Try to convert the string key into an array index. | 
 | 4511 |   if (key->AsArrayIndex(&index)) { | 
 | 4512 |     if (index < n) { | 
 | 4513 |       return frame->GetParameter(index); | 
 | 4514 |     } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4515 |       return isolate->initial_object_prototype()->GetElement(index); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4516 |     } | 
 | 4517 |   } | 
 | 4518 |  | 
 | 4519 |   // Handle special arguments properties. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4520 |   if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n); | 
 | 4521 |   if (key->Equals(isolate->heap()->callee_symbol())) { | 
 | 4522 |     Object* function = frame->function(); | 
 | 4523 |     if (function->IsJSFunction() && | 
 | 4524 |         JSFunction::cast(function)->shared()->strict_mode()) { | 
 | 4525 |       return isolate->Throw(*isolate->factory()->NewTypeError( | 
 | 4526 |           "strict_arguments_callee", HandleVector<Object>(NULL, 0))); | 
 | 4527 |     } | 
 | 4528 |     return function; | 
 | 4529 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4530 |  | 
 | 4531 |   // Lookup in the initial Object.prototype object. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4532 |   return isolate->initial_object_prototype()->GetProperty(*key); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4533 | } | 
 | 4534 |  | 
 | 4535 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4536 | RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4537 |   HandleScope scope(isolate); | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 4538 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4539 |   ASSERT(args.length() == 1); | 
 | 4540 |   Handle<Object> object = args.at<Object>(0); | 
 | 4541 |   if (object->IsJSObject()) { | 
 | 4542 |     Handle<JSObject> js_object = Handle<JSObject>::cast(object); | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 4543 |     if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 4544 |       MaybeObject* ok = js_object->TransformToFastProperties(0); | 
 | 4545 |       if (ok->IsRetryAfterGC()) return ok; | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 4546 |     } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4547 |   } | 
 | 4548 |   return *object; | 
 | 4549 | } | 
 | 4550 |  | 
 | 4551 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4552 | RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4553 |   HandleScope scope(isolate); | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 4554 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4555 |   ASSERT(args.length() == 1); | 
 | 4556 |   Handle<Object> object = args.at<Object>(0); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 4557 |   if (object->IsJSObject() && !object->IsJSGlobalProxy()) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4558 |     Handle<JSObject> js_object = Handle<JSObject>::cast(object); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 4559 |     NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4560 |   } | 
 | 4561 |   return *object; | 
 | 4562 | } | 
 | 4563 |  | 
 | 4564 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4565 | RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4566 |   NoHandleAllocation ha; | 
 | 4567 |   ASSERT(args.length() == 1); | 
 | 4568 |  | 
 | 4569 |   return args[0]->ToBoolean(); | 
 | 4570 | } | 
 | 4571 |  | 
 | 4572 |  | 
 | 4573 | // Returns the type string of a value; see ECMA-262, 11.4.3 (p 47). | 
 | 4574 | // Possible optimizations: put the type string into the oddballs. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4575 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4576 |   NoHandleAllocation ha; | 
 | 4577 |  | 
 | 4578 |   Object* obj = args[0]; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4579 |   if (obj->IsNumber()) return isolate->heap()->number_symbol(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4580 |   HeapObject* heap_obj = HeapObject::cast(obj); | 
 | 4581 |  | 
 | 4582 |   // typeof an undetectable object is 'undefined' | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4583 |   if (heap_obj->map()->is_undetectable()) { | 
 | 4584 |     return isolate->heap()->undefined_symbol(); | 
 | 4585 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4586 |  | 
 | 4587 |   InstanceType instance_type = heap_obj->map()->instance_type(); | 
 | 4588 |   if (instance_type < FIRST_NONSTRING_TYPE) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4589 |     return isolate->heap()->string_symbol(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4590 |   } | 
 | 4591 |  | 
 | 4592 |   switch (instance_type) { | 
 | 4593 |     case ODDBALL_TYPE: | 
 | 4594 |       if (heap_obj->IsTrue() || heap_obj->IsFalse()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4595 |         return isolate->heap()->boolean_symbol(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4596 |       } | 
 | 4597 |       if (heap_obj->IsNull()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4598 |         return isolate->heap()->object_symbol(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4599 |       } | 
 | 4600 |       ASSERT(heap_obj->IsUndefined()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4601 |       return isolate->heap()->undefined_symbol(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4602 |     case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE: | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4603 |       return isolate->heap()->function_symbol(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4604 |     default: | 
 | 4605 |       // For any kind of object not handled above, the spec rule for | 
 | 4606 |       // host objects gives that it is okay to return "object" | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4607 |       return isolate->heap()->object_symbol(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4608 |   } | 
 | 4609 | } | 
 | 4610 |  | 
 | 4611 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 4612 | static bool AreDigits(const char*s, int from, int to) { | 
 | 4613 |   for (int i = from; i < to; i++) { | 
 | 4614 |     if (s[i] < '0' || s[i] > '9') return false; | 
 | 4615 |   } | 
 | 4616 |  | 
 | 4617 |   return true; | 
 | 4618 | } | 
 | 4619 |  | 
 | 4620 |  | 
 | 4621 | static int ParseDecimalInteger(const char*s, int from, int to) { | 
 | 4622 |   ASSERT(to - from < 10);  // Overflow is not possible. | 
 | 4623 |   ASSERT(from < to); | 
 | 4624 |   int d = s[from] - '0'; | 
 | 4625 |  | 
 | 4626 |   for (int i = from + 1; i < to; i++) { | 
 | 4627 |     d = 10 * d + (s[i] - '0'); | 
 | 4628 |   } | 
 | 4629 |  | 
 | 4630 |   return d; | 
 | 4631 | } | 
 | 4632 |  | 
 | 4633 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4634 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4635 |   NoHandleAllocation ha; | 
 | 4636 |   ASSERT(args.length() == 1); | 
 | 4637 |   CONVERT_CHECKED(String, subject, args[0]); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 4638 |   subject->TryFlatten(); | 
 | 4639 |  | 
 | 4640 |   // Fast case: short integer or some sorts of junk values. | 
 | 4641 |   int len = subject->length(); | 
 | 4642 |   if (subject->IsSeqAsciiString()) { | 
 | 4643 |     if (len == 0) return Smi::FromInt(0); | 
 | 4644 |  | 
 | 4645 |     char const* data = SeqAsciiString::cast(subject)->GetChars(); | 
 | 4646 |     bool minus = (data[0] == '-'); | 
 | 4647 |     int start_pos = (minus ? 1 : 0); | 
 | 4648 |  | 
 | 4649 |     if (start_pos == len) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4650 |       return isolate->heap()->nan_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 4651 |     } else if (data[start_pos] > '9') { | 
 | 4652 |       // Fast check for a junk value. A valid string may start from a | 
 | 4653 |       // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or | 
 | 4654 |       // the 'I' character ('Infinity'). All of that have codes not greater than | 
 | 4655 |       // '9' except 'I'. | 
 | 4656 |       if (data[start_pos] != 'I') { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4657 |         return isolate->heap()->nan_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 4658 |       } | 
 | 4659 |     } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) { | 
 | 4660 |       // The maximal/minimal smi has 10 digits. If the string has less digits we | 
 | 4661 |       // know it will fit into the smi-data type. | 
 | 4662 |       int d = ParseDecimalInteger(data, start_pos, len); | 
 | 4663 |       if (minus) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4664 |         if (d == 0) return isolate->heap()->minus_zero_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 4665 |         d = -d; | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 4666 |       } else if (!subject->HasHashCode() && | 
 | 4667 |                  len <= String::kMaxArrayIndexSize && | 
 | 4668 |                  (len == 1 || data[0] != '0')) { | 
 | 4669 |         // String hash is not calculated yet but all the data are present. | 
 | 4670 |         // Update the hash field to speed up sequential convertions. | 
| Iain Merrick | 9ac36c9 | 2010-09-13 15:29:50 +0100 | [diff] [blame] | 4671 |         uint32_t hash = StringHasher::MakeArrayIndexHash(d, len); | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 4672 | #ifdef DEBUG | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 4673 |         subject->Hash();  // Force hash calculation. | 
 | 4674 |         ASSERT_EQ(static_cast<int>(subject->hash_field()), | 
 | 4675 |                   static_cast<int>(hash)); | 
 | 4676 | #endif | 
 | 4677 |         subject->set_hash_field(hash); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 4678 |       } | 
 | 4679 |       return Smi::FromInt(d); | 
 | 4680 |     } | 
 | 4681 |   } | 
 | 4682 |  | 
 | 4683 |   // Slower case. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4684 |   return isolate->heap()->NumberFromDouble( | 
 | 4685 |       StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4686 | } | 
 | 4687 |  | 
 | 4688 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4689 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4690 |   NoHandleAllocation ha; | 
 | 4691 |   ASSERT(args.length() == 1); | 
 | 4692 |  | 
 | 4693 |   CONVERT_CHECKED(JSArray, codes, args[0]); | 
 | 4694 |   int length = Smi::cast(codes->length())->value(); | 
 | 4695 |  | 
 | 4696 |   // Check if the string can be ASCII. | 
 | 4697 |   int i; | 
 | 4698 |   for (i = 0; i < length; i++) { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 4699 |     Object* element; | 
 | 4700 |     { MaybeObject* maybe_element = codes->GetElement(i); | 
 | 4701 |       // We probably can't get an exception here, but just in order to enforce | 
 | 4702 |       // the checking of inputs in the runtime calls we check here. | 
 | 4703 |       if (!maybe_element->ToObject(&element)) return maybe_element; | 
 | 4704 |     } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4705 |     CONVERT_NUMBER_CHECKED(int, chr, Int32, element); | 
 | 4706 |     if ((chr & 0xffff) > String::kMaxAsciiCharCode) | 
 | 4707 |       break; | 
 | 4708 |   } | 
 | 4709 |  | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 4710 |   MaybeObject* maybe_object = NULL; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4711 |   if (i == length) {  // The string is ASCII. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4712 |     maybe_object = isolate->heap()->AllocateRawAsciiString(length); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4713 |   } else {  // The string is not ASCII. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4714 |     maybe_object = isolate->heap()->AllocateRawTwoByteString(length); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4715 |   } | 
 | 4716 |  | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 4717 |   Object* object = NULL; | 
 | 4718 |   if (!maybe_object->ToObject(&object)) return maybe_object; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4719 |   String* result = String::cast(object); | 
 | 4720 |   for (int i = 0; i < length; i++) { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 4721 |     Object* element; | 
 | 4722 |     { MaybeObject* maybe_element = codes->GetElement(i); | 
 | 4723 |       if (!maybe_element->ToObject(&element)) return maybe_element; | 
 | 4724 |     } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4725 |     CONVERT_NUMBER_CHECKED(int, chr, Int32, element); | 
 | 4726 |     result->Set(i, chr & 0xffff); | 
 | 4727 |   } | 
 | 4728 |   return result; | 
 | 4729 | } | 
 | 4730 |  | 
 | 4731 |  | 
 | 4732 | // kNotEscaped is generated by the following: | 
 | 4733 | // | 
 | 4734 | // #!/bin/perl | 
 | 4735 | // for (my $i = 0; $i < 256; $i++) { | 
 | 4736 | //   print "\n" if $i % 16 == 0; | 
 | 4737 | //   my $c = chr($i); | 
 | 4738 | //   my $escaped = 1; | 
 | 4739 | //   $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#; | 
 | 4740 | //   print $escaped ? "0, " : "1, "; | 
 | 4741 | // } | 
 | 4742 |  | 
 | 4743 |  | 
 | 4744 | static bool IsNotEscaped(uint16_t character) { | 
 | 4745 |   // Only for 8 bit characters, the rest are always escaped (in a different way) | 
 | 4746 |   ASSERT(character < 256); | 
 | 4747 |   static const char kNotEscaped[256] = { | 
 | 4748 |     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
 | 4749 |     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
 | 4750 |     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, | 
 | 4751 |     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, | 
 | 4752 |     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 
 | 4753 |     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, | 
 | 4754 |     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 
 | 4755 |     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, | 
 | 4756 |     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
 | 4757 |     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
 | 4758 |     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
 | 4759 |     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
 | 4760 |     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
 | 4761 |     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
 | 4762 |     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
 | 4763 |     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
 | 4764 |   }; | 
 | 4765 |   return kNotEscaped[character] != 0; | 
 | 4766 | } | 
 | 4767 |  | 
 | 4768 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4769 | RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4770 |   const char hex_chars[] = "0123456789ABCDEF"; | 
 | 4771 |   NoHandleAllocation ha; | 
 | 4772 |   ASSERT(args.length() == 1); | 
 | 4773 |   CONVERT_CHECKED(String, source, args[0]); | 
 | 4774 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 4775 |   source->TryFlatten(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4776 |  | 
 | 4777 |   int escaped_length = 0; | 
 | 4778 |   int length = source->length(); | 
 | 4779 |   { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4780 |     Access<StringInputBuffer> buffer( | 
 | 4781 |         isolate->runtime_state()->string_input_buffer()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4782 |     buffer->Reset(source); | 
 | 4783 |     while (buffer->has_more()) { | 
 | 4784 |       uint16_t character = buffer->GetNext(); | 
 | 4785 |       if (character >= 256) { | 
 | 4786 |         escaped_length += 6; | 
 | 4787 |       } else if (IsNotEscaped(character)) { | 
 | 4788 |         escaped_length++; | 
 | 4789 |       } else { | 
 | 4790 |         escaped_length += 3; | 
 | 4791 |       } | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 4792 |       // We don't allow strings that are longer than a maximal length. | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 4793 |       ASSERT(String::kMaxLength < 0x7fffffff - 6);  // Cannot overflow. | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 4794 |       if (escaped_length > String::kMaxLength) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4795 |         isolate->context()->mark_out_of_memory(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4796 |         return Failure::OutOfMemoryException(); | 
 | 4797 |       } | 
 | 4798 |     } | 
 | 4799 |   } | 
 | 4800 |   // No length change implies no change.  Return original string if no change. | 
 | 4801 |   if (escaped_length == length) { | 
 | 4802 |     return source; | 
 | 4803 |   } | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 4804 |   Object* o; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4805 |   { MaybeObject* maybe_o = | 
 | 4806 |         isolate->heap()->AllocateRawAsciiString(escaped_length); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 4807 |     if (!maybe_o->ToObject(&o)) return maybe_o; | 
 | 4808 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4809 |   String* destination = String::cast(o); | 
 | 4810 |   int dest_position = 0; | 
 | 4811 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4812 |   Access<StringInputBuffer> buffer( | 
 | 4813 |       isolate->runtime_state()->string_input_buffer()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4814 |   buffer->Rewind(); | 
 | 4815 |   while (buffer->has_more()) { | 
 | 4816 |     uint16_t chr = buffer->GetNext(); | 
 | 4817 |     if (chr >= 256) { | 
 | 4818 |       destination->Set(dest_position, '%'); | 
 | 4819 |       destination->Set(dest_position+1, 'u'); | 
 | 4820 |       destination->Set(dest_position+2, hex_chars[chr >> 12]); | 
 | 4821 |       destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]); | 
 | 4822 |       destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]); | 
 | 4823 |       destination->Set(dest_position+5, hex_chars[chr & 0xf]); | 
 | 4824 |       dest_position += 6; | 
 | 4825 |     } else if (IsNotEscaped(chr)) { | 
 | 4826 |       destination->Set(dest_position, chr); | 
 | 4827 |       dest_position++; | 
 | 4828 |     } else { | 
 | 4829 |       destination->Set(dest_position, '%'); | 
 | 4830 |       destination->Set(dest_position+1, hex_chars[chr >> 4]); | 
 | 4831 |       destination->Set(dest_position+2, hex_chars[chr & 0xf]); | 
 | 4832 |       dest_position += 3; | 
 | 4833 |     } | 
 | 4834 |   } | 
 | 4835 |   return destination; | 
 | 4836 | } | 
 | 4837 |  | 
 | 4838 |  | 
 | 4839 | static inline int TwoDigitHex(uint16_t character1, uint16_t character2) { | 
 | 4840 |   static const signed char kHexValue['g'] = { | 
 | 4841 |     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 
 | 4842 |     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 
 | 4843 |     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 
 | 4844 |     0,  1,  2,   3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, | 
 | 4845 |     -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 
 | 4846 |     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 
 | 4847 |     -1, 10, 11, 12, 13, 14, 15 }; | 
 | 4848 |  | 
 | 4849 |   if (character1 > 'f') return -1; | 
 | 4850 |   int hi = kHexValue[character1]; | 
 | 4851 |   if (hi == -1) return -1; | 
 | 4852 |   if (character2 > 'f') return -1; | 
 | 4853 |   int lo = kHexValue[character2]; | 
 | 4854 |   if (lo == -1) return -1; | 
 | 4855 |   return (hi << 4) + lo; | 
 | 4856 | } | 
 | 4857 |  | 
 | 4858 |  | 
 | 4859 | static inline int Unescape(String* source, | 
 | 4860 |                            int i, | 
 | 4861 |                            int length, | 
 | 4862 |                            int* step) { | 
 | 4863 |   uint16_t character = source->Get(i); | 
 | 4864 |   int32_t hi = 0; | 
 | 4865 |   int32_t lo = 0; | 
 | 4866 |   if (character == '%' && | 
 | 4867 |       i <= length - 6 && | 
 | 4868 |       source->Get(i + 1) == 'u' && | 
 | 4869 |       (hi = TwoDigitHex(source->Get(i + 2), | 
 | 4870 |                         source->Get(i + 3))) != -1 && | 
 | 4871 |       (lo = TwoDigitHex(source->Get(i + 4), | 
 | 4872 |                         source->Get(i + 5))) != -1) { | 
 | 4873 |     *step = 6; | 
 | 4874 |     return (hi << 8) + lo; | 
 | 4875 |   } else if (character == '%' && | 
 | 4876 |       i <= length - 3 && | 
 | 4877 |       (lo = TwoDigitHex(source->Get(i + 1), | 
 | 4878 |                         source->Get(i + 2))) != -1) { | 
 | 4879 |     *step = 3; | 
 | 4880 |     return lo; | 
 | 4881 |   } else { | 
 | 4882 |     *step = 1; | 
 | 4883 |     return character; | 
 | 4884 |   } | 
 | 4885 | } | 
 | 4886 |  | 
 | 4887 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 4888 | RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4889 |   NoHandleAllocation ha; | 
 | 4890 |   ASSERT(args.length() == 1); | 
 | 4891 |   CONVERT_CHECKED(String, source, args[0]); | 
 | 4892 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 4893 |   source->TryFlatten(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4894 |  | 
 | 4895 |   bool ascii = true; | 
 | 4896 |   int length = source->length(); | 
 | 4897 |  | 
 | 4898 |   int unescaped_length = 0; | 
 | 4899 |   for (int i = 0; i < length; unescaped_length++) { | 
 | 4900 |     int step; | 
 | 4901 |     if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) { | 
 | 4902 |       ascii = false; | 
 | 4903 |     } | 
 | 4904 |     i += step; | 
 | 4905 |   } | 
 | 4906 |  | 
 | 4907 |   // No length change implies no change.  Return original string if no change. | 
 | 4908 |   if (unescaped_length == length) | 
 | 4909 |     return source; | 
 | 4910 |  | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 4911 |   Object* o; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 4912 |   { MaybeObject* maybe_o = | 
 | 4913 |         ascii ? | 
 | 4914 |         isolate->heap()->AllocateRawAsciiString(unescaped_length) : | 
 | 4915 |         isolate->heap()->AllocateRawTwoByteString(unescaped_length); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 4916 |     if (!maybe_o->ToObject(&o)) return maybe_o; | 
 | 4917 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4918 |   String* destination = String::cast(o); | 
 | 4919 |  | 
 | 4920 |   int dest_position = 0; | 
 | 4921 |   for (int i = 0; i < length; dest_position++) { | 
 | 4922 |     int step; | 
 | 4923 |     destination->Set(dest_position, Unescape(source, i, length, &step)); | 
 | 4924 |     i += step; | 
 | 4925 |   } | 
 | 4926 |   return destination; | 
 | 4927 | } | 
 | 4928 |  | 
 | 4929 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 4930 | static const unsigned int kQuoteTableLength = 128u; | 
 | 4931 |  | 
 | 4932 | static const int kJsonQuotesCharactersPerEntry = 8; | 
 | 4933 | static const char* const JsonQuotes = | 
 | 4934 |     "\\u0000  \\u0001  \\u0002  \\u0003  " | 
 | 4935 |     "\\u0004  \\u0005  \\u0006  \\u0007  " | 
 | 4936 |     "\\b      \\t      \\n      \\u000b  " | 
 | 4937 |     "\\f      \\r      \\u000e  \\u000f  " | 
 | 4938 |     "\\u0010  \\u0011  \\u0012  \\u0013  " | 
 | 4939 |     "\\u0014  \\u0015  \\u0016  \\u0017  " | 
 | 4940 |     "\\u0018  \\u0019  \\u001a  \\u001b  " | 
 | 4941 |     "\\u001c  \\u001d  \\u001e  \\u001f  " | 
 | 4942 |     "        !       \\\"      #       " | 
 | 4943 |     "$       %       &       '       " | 
 | 4944 |     "(       )       *       +       " | 
 | 4945 |     ",       -       .       /       " | 
 | 4946 |     "0       1       2       3       " | 
 | 4947 |     "4       5       6       7       " | 
 | 4948 |     "8       9       :       ;       " | 
 | 4949 |     "<       =       >       ?       " | 
 | 4950 |     "@       A       B       C       " | 
 | 4951 |     "D       E       F       G       " | 
 | 4952 |     "H       I       J       K       " | 
 | 4953 |     "L       M       N       O       " | 
 | 4954 |     "P       Q       R       S       " | 
 | 4955 |     "T       U       V       W       " | 
 | 4956 |     "X       Y       Z       [       " | 
 | 4957 |     "\\\\      ]       ^       _       " | 
 | 4958 |     "`       a       b       c       " | 
 | 4959 |     "d       e       f       g       " | 
 | 4960 |     "h       i       j       k       " | 
 | 4961 |     "l       m       n       o       " | 
 | 4962 |     "p       q       r       s       " | 
 | 4963 |     "t       u       v       w       " | 
 | 4964 |     "x       y       z       {       " | 
 | 4965 |     "|       }       ~       \177       "; | 
 | 4966 |  | 
 | 4967 |  | 
 | 4968 | // For a string that is less than 32k characters it should always be | 
 | 4969 | // possible to allocate it in new space. | 
 | 4970 | static const int kMaxGuaranteedNewSpaceString = 32 * 1024; | 
 | 4971 |  | 
 | 4972 |  | 
 | 4973 | // Doing JSON quoting cannot make the string more than this many times larger. | 
 | 4974 | static const int kJsonQuoteWorstCaseBlowup = 6; | 
 | 4975 |  | 
 | 4976 |  | 
 | 4977 | // Covers the entire ASCII range (all other characters are unchanged by JSON | 
 | 4978 | // quoting). | 
 | 4979 | static const byte JsonQuoteLengths[kQuoteTableLength] = { | 
 | 4980 |     6, 6, 6, 6, 6, 6, 6, 6, | 
 | 4981 |     2, 2, 2, 6, 2, 2, 6, 6, | 
 | 4982 |     6, 6, 6, 6, 6, 6, 6, 6, | 
 | 4983 |     6, 6, 6, 6, 6, 6, 6, 6, | 
 | 4984 |     1, 1, 2, 1, 1, 1, 1, 1, | 
 | 4985 |     1, 1, 1, 1, 1, 1, 1, 1, | 
 | 4986 |     1, 1, 1, 1, 1, 1, 1, 1, | 
 | 4987 |     1, 1, 1, 1, 1, 1, 1, 1, | 
 | 4988 |     1, 1, 1, 1, 1, 1, 1, 1, | 
 | 4989 |     1, 1, 1, 1, 1, 1, 1, 1, | 
 | 4990 |     1, 1, 1, 1, 1, 1, 1, 1, | 
 | 4991 |     1, 1, 1, 1, 2, 1, 1, 1, | 
 | 4992 |     1, 1, 1, 1, 1, 1, 1, 1, | 
 | 4993 |     1, 1, 1, 1, 1, 1, 1, 1, | 
 | 4994 |     1, 1, 1, 1, 1, 1, 1, 1, | 
 | 4995 |     1, 1, 1, 1, 1, 1, 1, 1, | 
 | 4996 | }; | 
 | 4997 |  | 
 | 4998 |  | 
 | 4999 | template <typename StringType> | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5000 | MaybeObject* AllocateRawString(Isolate* isolate, int length); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5001 |  | 
 | 5002 |  | 
 | 5003 | template <> | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5004 | MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) { | 
 | 5005 |   return isolate->heap()->AllocateRawTwoByteString(length); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5006 | } | 
 | 5007 |  | 
 | 5008 |  | 
 | 5009 | template <> | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5010 | MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) { | 
 | 5011 |   return isolate->heap()->AllocateRawAsciiString(length); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5012 | } | 
 | 5013 |  | 
 | 5014 |  | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 5015 | template <typename Char, typename StringType, bool comma> | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5016 | static MaybeObject* SlowQuoteJsonString(Isolate* isolate, | 
 | 5017 |                                         Vector<const Char> characters) { | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5018 |   int length = characters.length(); | 
 | 5019 |   const Char* read_cursor = characters.start(); | 
 | 5020 |   const Char* end = read_cursor + length; | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 5021 |   const int kSpaceForQuotes = 2 + (comma ? 1 :0); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5022 |   int quoted_length = kSpaceForQuotes; | 
 | 5023 |   while (read_cursor < end) { | 
 | 5024 |     Char c = *(read_cursor++); | 
 | 5025 |     if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) { | 
 | 5026 |       quoted_length++; | 
 | 5027 |     } else { | 
 | 5028 |       quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)]; | 
 | 5029 |     } | 
 | 5030 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5031 |   MaybeObject* new_alloc = AllocateRawString<StringType>(isolate, | 
 | 5032 |                                                          quoted_length); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5033 |   Object* new_object; | 
 | 5034 |   if (!new_alloc->ToObject(&new_object)) { | 
 | 5035 |     return new_alloc; | 
 | 5036 |   } | 
 | 5037 |   StringType* new_string = StringType::cast(new_object); | 
 | 5038 |  | 
 | 5039 |   Char* write_cursor = reinterpret_cast<Char*>( | 
 | 5040 |       new_string->address() + SeqAsciiString::kHeaderSize); | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 5041 |   if (comma) *(write_cursor++) = ','; | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5042 |   *(write_cursor++) = '"'; | 
 | 5043 |  | 
 | 5044 |   read_cursor = characters.start(); | 
 | 5045 |   while (read_cursor < end) { | 
 | 5046 |     Char c = *(read_cursor++); | 
 | 5047 |     if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) { | 
 | 5048 |       *(write_cursor++) = c; | 
 | 5049 |     } else { | 
 | 5050 |       int len = JsonQuoteLengths[static_cast<unsigned>(c)]; | 
 | 5051 |       const char* replacement = JsonQuotes + | 
 | 5052 |           static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry; | 
 | 5053 |       for (int i = 0; i < len; i++) { | 
 | 5054 |         *write_cursor++ = *replacement++; | 
 | 5055 |       } | 
 | 5056 |     } | 
 | 5057 |   } | 
 | 5058 |   *(write_cursor++) = '"'; | 
 | 5059 |   return new_string; | 
 | 5060 | } | 
 | 5061 |  | 
 | 5062 |  | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 5063 | template <typename Char, typename StringType, bool comma> | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5064 | static MaybeObject* QuoteJsonString(Isolate* isolate, | 
 | 5065 |                                     Vector<const Char> characters) { | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5066 |   int length = characters.length(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5067 |   isolate->counters()->quote_json_char_count()->Increment(length); | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 5068 |   const int kSpaceForQuotes = 2 + (comma ? 1 :0); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5069 |   int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes; | 
 | 5070 |   if (worst_case_length > kMaxGuaranteedNewSpaceString) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5071 |     return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5072 |   } | 
 | 5073 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5074 |   MaybeObject* new_alloc = AllocateRawString<StringType>(isolate, | 
 | 5075 |                                                          worst_case_length); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5076 |   Object* new_object; | 
 | 5077 |   if (!new_alloc->ToObject(&new_object)) { | 
 | 5078 |     return new_alloc; | 
 | 5079 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5080 |   if (!isolate->heap()->new_space()->Contains(new_object)) { | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5081 |     // Even if our string is small enough to fit in new space we still have to | 
 | 5082 |     // handle it being allocated in old space as may happen in the third | 
 | 5083 |     // attempt.  See CALL_AND_RETRY in heap-inl.h and similar code in | 
 | 5084 |     // CEntryStub::GenerateCore. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5085 |     return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5086 |   } | 
 | 5087 |   StringType* new_string = StringType::cast(new_object); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5088 |   ASSERT(isolate->heap()->new_space()->Contains(new_string)); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5089 |  | 
 | 5090 |   STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); | 
 | 5091 |   Char* write_cursor = reinterpret_cast<Char*>( | 
 | 5092 |       new_string->address() + SeqAsciiString::kHeaderSize); | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 5093 |   if (comma) *(write_cursor++) = ','; | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5094 |   *(write_cursor++) = '"'; | 
 | 5095 |  | 
 | 5096 |   const Char* read_cursor = characters.start(); | 
 | 5097 |   const Char* end = read_cursor + length; | 
 | 5098 |   while (read_cursor < end) { | 
 | 5099 |     Char c = *(read_cursor++); | 
 | 5100 |     if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) { | 
 | 5101 |       *(write_cursor++) = c; | 
 | 5102 |     } else { | 
 | 5103 |       int len = JsonQuoteLengths[static_cast<unsigned>(c)]; | 
 | 5104 |       const char* replacement = JsonQuotes + | 
 | 5105 |           static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry; | 
 | 5106 |       write_cursor[0] = replacement[0]; | 
 | 5107 |       if (len > 1) { | 
 | 5108 |         write_cursor[1] = replacement[1]; | 
 | 5109 |         if (len > 2) { | 
 | 5110 |           ASSERT(len == 6); | 
 | 5111 |           write_cursor[2] = replacement[2]; | 
 | 5112 |           write_cursor[3] = replacement[3]; | 
 | 5113 |           write_cursor[4] = replacement[4]; | 
 | 5114 |           write_cursor[5] = replacement[5]; | 
 | 5115 |         } | 
 | 5116 |       } | 
 | 5117 |       write_cursor += len; | 
 | 5118 |     } | 
 | 5119 |   } | 
 | 5120 |   *(write_cursor++) = '"'; | 
 | 5121 |  | 
 | 5122 |   int final_length = static_cast<int>( | 
 | 5123 |       write_cursor - reinterpret_cast<Char*>( | 
 | 5124 |           new_string->address() + SeqAsciiString::kHeaderSize)); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5125 |   isolate->heap()->new_space()-> | 
 | 5126 |       template ShrinkStringAtAllocationBoundary<StringType>( | 
 | 5127 |           new_string, final_length); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5128 |   return new_string; | 
 | 5129 | } | 
 | 5130 |  | 
 | 5131 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5132 | RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) { | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5133 |   NoHandleAllocation ha; | 
 | 5134 |   CONVERT_CHECKED(String, str, args[0]); | 
 | 5135 |   if (!str->IsFlat()) { | 
 | 5136 |     MaybeObject* try_flatten = str->TryFlatten(); | 
 | 5137 |     Object* flat; | 
 | 5138 |     if (!try_flatten->ToObject(&flat)) { | 
 | 5139 |       return try_flatten; | 
 | 5140 |     } | 
 | 5141 |     str = String::cast(flat); | 
 | 5142 |     ASSERT(str->IsFlat()); | 
 | 5143 |   } | 
 | 5144 |   if (str->IsTwoByteRepresentation()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5145 |     return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate, | 
 | 5146 |                                                           str->ToUC16Vector()); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5147 |   } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5148 |     return QuoteJsonString<char, SeqAsciiString, false>(isolate, | 
 | 5149 |                                                         str->ToAsciiVector()); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5150 |   } | 
 | 5151 | } | 
 | 5152 |  | 
 | 5153 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5154 | RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) { | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 5155 |   NoHandleAllocation ha; | 
 | 5156 |   CONVERT_CHECKED(String, str, args[0]); | 
 | 5157 |   if (!str->IsFlat()) { | 
 | 5158 |     MaybeObject* try_flatten = str->TryFlatten(); | 
 | 5159 |     Object* flat; | 
 | 5160 |     if (!try_flatten->ToObject(&flat)) { | 
 | 5161 |       return try_flatten; | 
 | 5162 |     } | 
 | 5163 |     str = String::cast(flat); | 
 | 5164 |     ASSERT(str->IsFlat()); | 
 | 5165 |   } | 
 | 5166 |   if (str->IsTwoByteRepresentation()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5167 |     return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate, | 
 | 5168 |                                                          str->ToUC16Vector()); | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 5169 |   } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5170 |     return QuoteJsonString<char, SeqAsciiString, true>(isolate, | 
 | 5171 |                                                        str->ToAsciiVector()); | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 5172 |   } | 
 | 5173 | } | 
 | 5174 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5175 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5176 |   NoHandleAllocation ha; | 
 | 5177 |  | 
 | 5178 |   CONVERT_CHECKED(String, s, args[0]); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 5179 |   CONVERT_SMI_CHECKED(radix, args[1]); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5180 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5181 |   s->TryFlatten(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5182 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5183 |   RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5184 |   double value = StringToInt(isolate->unicode_cache(), s, radix); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5185 |   return isolate->heap()->NumberFromDouble(value); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5186 | } | 
 | 5187 |  | 
 | 5188 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5189 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5190 |   NoHandleAllocation ha; | 
 | 5191 |   CONVERT_CHECKED(String, str, args[0]); | 
 | 5192 |  | 
 | 5193 |   // ECMA-262 section 15.1.2.3, empty string is NaN | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5194 |   double value = StringToDouble(isolate->unicode_cache(), | 
 | 5195 |                                 str, ALLOW_TRAILING_JUNK, OS::nan_value()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5196 |  | 
 | 5197 |   // Create a number object from the value. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5198 |   return isolate->heap()->NumberFromDouble(value); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5199 | } | 
 | 5200 |  | 
 | 5201 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5202 | template <class Converter> | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5203 | MUST_USE_RESULT static MaybeObject* ConvertCaseHelper( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5204 |     Isolate* isolate, | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5205 |     String* s, | 
 | 5206 |     int length, | 
 | 5207 |     int input_string_length, | 
 | 5208 |     unibrow::Mapping<Converter, 128>* mapping) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5209 |   // We try this twice, once with the assumption that the result is no longer | 
 | 5210 |   // than the input and, if that assumption breaks, again with the exact | 
 | 5211 |   // length.  This may not be pretty, but it is nicer than what was here before | 
 | 5212 |   // and I hereby claim my vaffel-is. | 
 | 5213 |   // | 
 | 5214 |   // Allocate the resulting string. | 
 | 5215 |   // | 
 | 5216 |   // NOTE: This assumes that the upper/lower case of an ascii | 
 | 5217 |   // character is also ascii.  This is currently the case, but it | 
 | 5218 |   // might break in the future if we implement more context and locale | 
 | 5219 |   // dependent upper/lower conversions. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5220 |   Object* o; | 
 | 5221 |   { MaybeObject* maybe_o = s->IsAsciiRepresentation() | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5222 |         ? isolate->heap()->AllocateRawAsciiString(length) | 
 | 5223 |         : isolate->heap()->AllocateRawTwoByteString(length); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5224 |     if (!maybe_o->ToObject(&o)) return maybe_o; | 
 | 5225 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5226 |   String* result = String::cast(o); | 
 | 5227 |   bool has_changed_character = false; | 
 | 5228 |  | 
 | 5229 |   // Convert all characters to upper case, assuming that they will fit | 
 | 5230 |   // in the buffer | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5231 |   Access<StringInputBuffer> buffer( | 
 | 5232 |       isolate->runtime_state()->string_input_buffer()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5233 |   buffer->Reset(s); | 
 | 5234 |   unibrow::uchar chars[Converter::kMaxWidth]; | 
 | 5235 |   // We can assume that the string is not empty | 
 | 5236 |   uc32 current = buffer->GetNext(); | 
 | 5237 |   for (int i = 0; i < length;) { | 
 | 5238 |     bool has_next = buffer->has_more(); | 
 | 5239 |     uc32 next = has_next ? buffer->GetNext() : 0; | 
 | 5240 |     int char_length = mapping->get(current, next, chars); | 
 | 5241 |     if (char_length == 0) { | 
 | 5242 |       // The case conversion of this character is the character itself. | 
 | 5243 |       result->Set(i, current); | 
 | 5244 |       i++; | 
 | 5245 |     } else if (char_length == 1) { | 
 | 5246 |       // Common case: converting the letter resulted in one character. | 
 | 5247 |       ASSERT(static_cast<uc32>(chars[0]) != current); | 
 | 5248 |       result->Set(i, chars[0]); | 
 | 5249 |       has_changed_character = true; | 
 | 5250 |       i++; | 
 | 5251 |     } else if (length == input_string_length) { | 
 | 5252 |       // We've assumed that the result would be as long as the | 
 | 5253 |       // input but here is a character that converts to several | 
 | 5254 |       // characters.  No matter, we calculate the exact length | 
 | 5255 |       // of the result and try the whole thing again. | 
 | 5256 |       // | 
 | 5257 |       // Note that this leaves room for optimization.  We could just | 
 | 5258 |       // memcpy what we already have to the result string.  Also, | 
 | 5259 |       // the result string is the last object allocated we could | 
 | 5260 |       // "realloc" it and probably, in the vast majority of cases, | 
 | 5261 |       // extend the existing string to be able to hold the full | 
 | 5262 |       // result. | 
 | 5263 |       int next_length = 0; | 
 | 5264 |       if (has_next) { | 
 | 5265 |         next_length = mapping->get(next, 0, chars); | 
 | 5266 |         if (next_length == 0) next_length = 1; | 
 | 5267 |       } | 
 | 5268 |       int current_length = i + char_length + next_length; | 
 | 5269 |       while (buffer->has_more()) { | 
 | 5270 |         current = buffer->GetNext(); | 
 | 5271 |         // NOTE: we use 0 as the next character here because, while | 
 | 5272 |         // the next character may affect what a character converts to, | 
 | 5273 |         // it does not in any case affect the length of what it convert | 
 | 5274 |         // to. | 
 | 5275 |         int char_length = mapping->get(current, 0, chars); | 
 | 5276 |         if (char_length == 0) char_length = 1; | 
 | 5277 |         current_length += char_length; | 
 | 5278 |         if (current_length > Smi::kMaxValue) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5279 |           isolate->context()->mark_out_of_memory(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5280 |           return Failure::OutOfMemoryException(); | 
 | 5281 |         } | 
 | 5282 |       } | 
 | 5283 |       // Try again with the real length. | 
 | 5284 |       return Smi::FromInt(current_length); | 
 | 5285 |     } else { | 
 | 5286 |       for (int j = 0; j < char_length; j++) { | 
 | 5287 |         result->Set(i, chars[j]); | 
 | 5288 |         i++; | 
 | 5289 |       } | 
 | 5290 |       has_changed_character = true; | 
 | 5291 |     } | 
 | 5292 |     current = next; | 
 | 5293 |   } | 
 | 5294 |   if (has_changed_character) { | 
 | 5295 |     return result; | 
 | 5296 |   } else { | 
 | 5297 |     // If we didn't actually change anything in doing the conversion | 
 | 5298 |     // we simple return the result and let the converted string | 
 | 5299 |     // become garbage; there is no reason to keep two identical strings | 
 | 5300 |     // alive. | 
 | 5301 |     return s; | 
 | 5302 |   } | 
 | 5303 | } | 
 | 5304 |  | 
 | 5305 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5306 | namespace { | 
 | 5307 |  | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5308 | static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF; | 
 | 5309 |  | 
 | 5310 |  | 
 | 5311 | // Given a word and two range boundaries returns a word with high bit | 
 | 5312 | // set in every byte iff the corresponding input byte was strictly in | 
 | 5313 | // the range (m, n). All the other bits in the result are cleared. | 
 | 5314 | // This function is only useful when it can be inlined and the | 
 | 5315 | // boundaries are statically known. | 
 | 5316 | // Requires: all bytes in the input word and the boundaries must be | 
 | 5317 | // ascii (less than 0x7F). | 
 | 5318 | static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) { | 
 | 5319 |   // Every byte in an ascii string is less than or equal to 0x7F. | 
 | 5320 |   ASSERT((w & (kOneInEveryByte * 0x7F)) == w); | 
 | 5321 |   // Use strict inequalities since in edge cases the function could be | 
 | 5322 |   // further simplified. | 
 | 5323 |   ASSERT(0 < m && m < n && n < 0x7F); | 
 | 5324 |   // Has high bit set in every w byte less than n. | 
 | 5325 |   uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w; | 
 | 5326 |   // Has high bit set in every w byte greater than m. | 
 | 5327 |   uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m); | 
 | 5328 |   return (tmp1 & tmp2 & (kOneInEveryByte * 0x80)); | 
 | 5329 | } | 
 | 5330 |  | 
 | 5331 |  | 
 | 5332 | enum AsciiCaseConversion { | 
 | 5333 |   ASCII_TO_LOWER, | 
 | 5334 |   ASCII_TO_UPPER | 
 | 5335 | }; | 
 | 5336 |  | 
 | 5337 |  | 
 | 5338 | template <AsciiCaseConversion dir> | 
 | 5339 | struct FastAsciiConverter { | 
 | 5340 |   static bool Convert(char* dst, char* src, int length) { | 
 | 5341 | #ifdef DEBUG | 
 | 5342 |     char* saved_dst = dst; | 
 | 5343 |     char* saved_src = src; | 
 | 5344 | #endif | 
 | 5345 |     // We rely on the distance between upper and lower case letters | 
 | 5346 |     // being a known power of 2. | 
 | 5347 |     ASSERT('a' - 'A' == (1 << 5)); | 
 | 5348 |     // Boundaries for the range of input characters than require conversion. | 
 | 5349 |     const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1; | 
 | 5350 |     const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1; | 
 | 5351 |     bool changed = false; | 
 | 5352 |     char* const limit = src + length; | 
 | 5353 | #ifdef V8_HOST_CAN_READ_UNALIGNED | 
 | 5354 |     // Process the prefix of the input that requires no conversion one | 
 | 5355 |     // (machine) word at a time. | 
 | 5356 |     while (src <= limit - sizeof(uintptr_t)) { | 
 | 5357 |       uintptr_t w = *reinterpret_cast<uintptr_t*>(src); | 
 | 5358 |       if (AsciiRangeMask(w, lo, hi) != 0) { | 
 | 5359 |         changed = true; | 
 | 5360 |         break; | 
 | 5361 |       } | 
 | 5362 |       *reinterpret_cast<uintptr_t*>(dst) = w; | 
 | 5363 |       src += sizeof(uintptr_t); | 
 | 5364 |       dst += sizeof(uintptr_t); | 
 | 5365 |     } | 
 | 5366 |     // Process the remainder of the input performing conversion when | 
 | 5367 |     // required one word at a time. | 
 | 5368 |     while (src <= limit - sizeof(uintptr_t)) { | 
 | 5369 |       uintptr_t w = *reinterpret_cast<uintptr_t*>(src); | 
 | 5370 |       uintptr_t m = AsciiRangeMask(w, lo, hi); | 
 | 5371 |       // The mask has high (7th) bit set in every byte that needs | 
 | 5372 |       // conversion and we know that the distance between cases is | 
 | 5373 |       // 1 << 5. | 
 | 5374 |       *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2); | 
 | 5375 |       src += sizeof(uintptr_t); | 
 | 5376 |       dst += sizeof(uintptr_t); | 
 | 5377 |     } | 
 | 5378 | #endif | 
 | 5379 |     // Process the last few bytes of the input (or the whole input if | 
 | 5380 |     // unaligned access is not supported). | 
 | 5381 |     while (src < limit) { | 
 | 5382 |       char c = *src; | 
 | 5383 |       if (lo < c && c < hi) { | 
 | 5384 |         c ^= (1 << 5); | 
 | 5385 |         changed = true; | 
 | 5386 |       } | 
 | 5387 |       *dst = c; | 
 | 5388 |       ++src; | 
 | 5389 |       ++dst; | 
 | 5390 |     } | 
 | 5391 | #ifdef DEBUG | 
 | 5392 |     CheckConvert(saved_dst, saved_src, length, changed); | 
 | 5393 | #endif | 
 | 5394 |     return changed; | 
 | 5395 |   } | 
 | 5396 |  | 
 | 5397 | #ifdef DEBUG | 
 | 5398 |   static void CheckConvert(char* dst, char* src, int length, bool changed) { | 
 | 5399 |     bool expected_changed = false; | 
 | 5400 |     for (int i = 0; i < length; i++) { | 
 | 5401 |       if (dst[i] == src[i]) continue; | 
 | 5402 |       expected_changed = true; | 
 | 5403 |       if (dir == ASCII_TO_LOWER) { | 
 | 5404 |         ASSERT('A' <= src[i] && src[i] <= 'Z'); | 
 | 5405 |         ASSERT(dst[i] == src[i] + ('a' - 'A')); | 
 | 5406 |       } else { | 
 | 5407 |         ASSERT(dir == ASCII_TO_UPPER); | 
 | 5408 |         ASSERT('a' <= src[i] && src[i] <= 'z'); | 
 | 5409 |         ASSERT(dst[i] == src[i] - ('a' - 'A')); | 
 | 5410 |       } | 
 | 5411 |     } | 
 | 5412 |     ASSERT(expected_changed == changed); | 
 | 5413 |   } | 
 | 5414 | #endif | 
 | 5415 | }; | 
 | 5416 |  | 
 | 5417 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5418 | struct ToLowerTraits { | 
 | 5419 |   typedef unibrow::ToLowercase UnibrowConverter; | 
 | 5420 |  | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5421 |   typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter; | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5422 | }; | 
 | 5423 |  | 
 | 5424 |  | 
 | 5425 | struct ToUpperTraits { | 
 | 5426 |   typedef unibrow::ToUppercase UnibrowConverter; | 
 | 5427 |  | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5428 |   typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter; | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5429 | }; | 
 | 5430 |  | 
 | 5431 | }  // namespace | 
 | 5432 |  | 
 | 5433 |  | 
 | 5434 | template <typename ConvertTraits> | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5435 | MUST_USE_RESULT static MaybeObject* ConvertCase( | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5436 |     Arguments args, | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5437 |     Isolate* isolate, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5438 |     unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5439 |   NoHandleAllocation ha; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5440 |   CONVERT_CHECKED(String, s, args[0]); | 
| Kristian Monsen | 9dcf7e2 | 2010-06-28 14:14:28 +0100 | [diff] [blame] | 5441 |   s = s->TryFlattenGetString(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5442 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5443 |   const int length = s->length(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5444 |   // Assume that the string is not empty; we need this assumption later | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5445 |   if (length == 0) return s; | 
 | 5446 |  | 
 | 5447 |   // Simpler handling of ascii strings. | 
 | 5448 |   // | 
 | 5449 |   // NOTE: This assumes that the upper/lower case of an ascii | 
 | 5450 |   // character is also ascii.  This is currently the case, but it | 
 | 5451 |   // might break in the future if we implement more context and locale | 
 | 5452 |   // dependent upper/lower conversions. | 
| Kristian Monsen | 9dcf7e2 | 2010-06-28 14:14:28 +0100 | [diff] [blame] | 5453 |   if (s->IsSeqAsciiString()) { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5454 |     Object* o; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5455 |     { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5456 |       if (!maybe_o->ToObject(&o)) return maybe_o; | 
 | 5457 |     } | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5458 |     SeqAsciiString* result = SeqAsciiString::cast(o); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5459 |     bool has_changed_character = ConvertTraits::AsciiConverter::Convert( | 
| Kristian Monsen | 9dcf7e2 | 2010-06-28 14:14:28 +0100 | [diff] [blame] | 5460 |         result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5461 |     return has_changed_character ? result : s; | 
 | 5462 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5463 |  | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5464 |   Object* answer; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5465 |   { MaybeObject* maybe_answer = | 
 | 5466 |         ConvertCaseHelper(isolate, s, length, length, mapping); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5467 |     if (!maybe_answer->ToObject(&answer)) return maybe_answer; | 
 | 5468 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5469 |   if (answer->IsSmi()) { | 
 | 5470 |     // Retry with correct length. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5471 |     { MaybeObject* maybe_answer = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5472 |           ConvertCaseHelper(isolate, | 
 | 5473 |                             s, Smi::cast(answer)->value(), length, mapping); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5474 |       if (!maybe_answer->ToObject(&answer)) return maybe_answer; | 
 | 5475 |     } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5476 |   } | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5477 |   return answer; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5478 | } | 
 | 5479 |  | 
 | 5480 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5481 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5482 |   return ConvertCase<ToLowerTraits>( | 
 | 5483 |       args, isolate, isolate->runtime_state()->to_lower_mapping()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5484 | } | 
 | 5485 |  | 
 | 5486 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5487 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5488 |   return ConvertCase<ToUpperTraits>( | 
 | 5489 |       args, isolate, isolate->runtime_state()->to_upper_mapping()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5490 | } | 
 | 5491 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5492 |  | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 5493 | static inline bool IsTrimWhiteSpace(unibrow::uchar c) { | 
 | 5494 |   return unibrow::WhiteSpace::Is(c) || c == 0x200b; | 
 | 5495 | } | 
 | 5496 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5497 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5498 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) { | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 5499 |   NoHandleAllocation ha; | 
 | 5500 |   ASSERT(args.length() == 3); | 
 | 5501 |  | 
 | 5502 |   CONVERT_CHECKED(String, s, args[0]); | 
 | 5503 |   CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]); | 
 | 5504 |   CONVERT_BOOLEAN_CHECKED(trimRight, args[2]); | 
 | 5505 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5506 |   s->TryFlatten(); | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 5507 |   int length = s->length(); | 
 | 5508 |  | 
 | 5509 |   int left = 0; | 
 | 5510 |   if (trimLeft) { | 
 | 5511 |     while (left < length && IsTrimWhiteSpace(s->Get(left))) { | 
 | 5512 |       left++; | 
 | 5513 |     } | 
 | 5514 |   } | 
 | 5515 |  | 
 | 5516 |   int right = length; | 
 | 5517 |   if (trimRight) { | 
 | 5518 |     while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) { | 
 | 5519 |       right--; | 
 | 5520 |     } | 
 | 5521 |   } | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 5522 |   return s->SubString(left, right); | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 5523 | } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5524 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5525 |  | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 5526 | template <typename SubjectChar, typename PatternChar> | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5527 | void FindStringIndices(Isolate* isolate, | 
 | 5528 |                        Vector<const SubjectChar> subject, | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 5529 |                        Vector<const PatternChar> pattern, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5530 |                        ZoneList<int>* indices, | 
 | 5531 |                        unsigned int limit) { | 
 | 5532 |   ASSERT(limit > 0); | 
 | 5533 |   // Collect indices of pattern in subject, and the end-of-string index. | 
 | 5534 |   // Stop after finding at most limit values. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5535 |   StringSearch<PatternChar, SubjectChar> search(isolate, pattern); | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 5536 |   int pattern_length = pattern.length(); | 
 | 5537 |   int index = 0; | 
 | 5538 |   while (limit > 0) { | 
 | 5539 |     index = search.Search(subject, index); | 
 | 5540 |     if (index < 0) return; | 
 | 5541 |     indices->Add(index); | 
 | 5542 |     index += pattern_length; | 
 | 5543 |     limit--; | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5544 |   } | 
 | 5545 | } | 
 | 5546 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5547 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5548 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5549 |   ASSERT(args.length() == 3); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5550 |   HandleScope handle_scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5551 |   CONVERT_ARG_CHECKED(String, subject, 0); | 
 | 5552 |   CONVERT_ARG_CHECKED(String, pattern, 1); | 
 | 5553 |   CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]); | 
 | 5554 |  | 
 | 5555 |   int subject_length = subject->length(); | 
 | 5556 |   int pattern_length = pattern->length(); | 
 | 5557 |   RUNTIME_ASSERT(pattern_length > 0); | 
 | 5558 |  | 
 | 5559 |   // The limit can be very large (0xffffffffu), but since the pattern | 
 | 5560 |   // isn't empty, we can never create more parts than ~half the length | 
 | 5561 |   // of the subject. | 
 | 5562 |  | 
 | 5563 |   if (!subject->IsFlat()) FlattenString(subject); | 
 | 5564 |  | 
 | 5565 |   static const int kMaxInitialListCapacity = 16; | 
 | 5566 |  | 
 | 5567 |   ZoneScope scope(DELETE_ON_EXIT); | 
 | 5568 |  | 
 | 5569 |   // Find (up to limit) indices of separator and end-of-string in subject | 
 | 5570 |   int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit); | 
 | 5571 |   ZoneList<int> indices(initial_capacity); | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 5572 |   if (!pattern->IsFlat()) FlattenString(pattern); | 
 | 5573 |  | 
 | 5574 |   // No allocation block. | 
 | 5575 |   { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5576 |     AssertNoAllocation nogc; | 
 | 5577 |     if (subject->IsAsciiRepresentation()) { | 
 | 5578 |       Vector<const char> subject_vector = subject->ToAsciiVector(); | 
 | 5579 |       if (pattern->IsAsciiRepresentation()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5580 |         FindStringIndices(isolate, | 
 | 5581 |                           subject_vector, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5582 |                           pattern->ToAsciiVector(), | 
 | 5583 |                           &indices, | 
 | 5584 |                           limit); | 
 | 5585 |       } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5586 |         FindStringIndices(isolate, | 
 | 5587 |                           subject_vector, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5588 |                           pattern->ToUC16Vector(), | 
 | 5589 |                           &indices, | 
 | 5590 |                           limit); | 
 | 5591 |       } | 
 | 5592 |     } else { | 
 | 5593 |       Vector<const uc16> subject_vector = subject->ToUC16Vector(); | 
 | 5594 |       if (pattern->IsAsciiRepresentation()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5595 |         FindStringIndices(isolate, | 
 | 5596 |                           subject_vector, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5597 |                           pattern->ToAsciiVector(), | 
 | 5598 |                           &indices, | 
 | 5599 |                           limit); | 
 | 5600 |       } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5601 |         FindStringIndices(isolate, | 
 | 5602 |                           subject_vector, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5603 |                           pattern->ToUC16Vector(), | 
 | 5604 |                           &indices, | 
 | 5605 |                           limit); | 
 | 5606 |       } | 
 | 5607 |     } | 
 | 5608 |   } | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 5609 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5610 |   if (static_cast<uint32_t>(indices.length()) < limit) { | 
 | 5611 |     indices.Add(subject_length); | 
 | 5612 |   } | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5613 |  | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 5614 |   // The list indices now contains the end of each part to create. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5615 |  | 
 | 5616 |   // Create JSArray of substrings separated by separator. | 
 | 5617 |   int part_count = indices.length(); | 
 | 5618 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5619 |   Handle<JSArray> result = isolate->factory()->NewJSArray(part_count); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5620 |   result->set_length(Smi::FromInt(part_count)); | 
 | 5621 |  | 
 | 5622 |   ASSERT(result->HasFastElements()); | 
 | 5623 |  | 
 | 5624 |   if (part_count == 1 && indices.at(0) == subject_length) { | 
 | 5625 |     FixedArray::cast(result->elements())->set(0, *subject); | 
 | 5626 |     return *result; | 
 | 5627 |   } | 
 | 5628 |  | 
 | 5629 |   Handle<FixedArray> elements(FixedArray::cast(result->elements())); | 
 | 5630 |   int part_start = 0; | 
 | 5631 |   for (int i = 0; i < part_count; i++) { | 
 | 5632 |     HandleScope local_loop_handle; | 
 | 5633 |     int part_end = indices.at(i); | 
 | 5634 |     Handle<String> substring = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5635 |         isolate->factory()->NewSubString(subject, part_start, part_end); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5636 |     elements->set(i, *substring); | 
 | 5637 |     part_start = part_end + pattern_length; | 
 | 5638 |   } | 
 | 5639 |  | 
 | 5640 |   return *result; | 
 | 5641 | } | 
 | 5642 |  | 
 | 5643 |  | 
 | 5644 | // Copies ascii characters to the given fixed array looking up | 
 | 5645 | // one-char strings in the cache. Gives up on the first char that is | 
 | 5646 | // not in the cache and fills the remainder with smi zeros. Returns | 
 | 5647 | // the length of the successfully copied prefix. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5648 | static int CopyCachedAsciiCharsToArray(Heap* heap, | 
 | 5649 |                                        const char* chars, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5650 |                                        FixedArray* elements, | 
 | 5651 |                                        int length) { | 
 | 5652 |   AssertNoAllocation nogc; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5653 |   FixedArray* ascii_cache = heap->single_character_string_cache(); | 
 | 5654 |   Object* undefined = heap->undefined_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5655 |   int i; | 
 | 5656 |   for (i = 0; i < length; ++i) { | 
 | 5657 |     Object* value = ascii_cache->get(chars[i]); | 
 | 5658 |     if (value == undefined) break; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5659 |     ASSERT(!heap->InNewSpace(value)); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5660 |     elements->set(i, value, SKIP_WRITE_BARRIER); | 
 | 5661 |   } | 
 | 5662 |   if (i < length) { | 
 | 5663 |     ASSERT(Smi::FromInt(0) == 0); | 
 | 5664 |     memset(elements->data_start() + i, 0, kPointerSize * (length - i)); | 
 | 5665 |   } | 
 | 5666 | #ifdef DEBUG | 
 | 5667 |   for (int j = 0; j < length; ++j) { | 
 | 5668 |     Object* element = elements->get(j); | 
 | 5669 |     ASSERT(element == Smi::FromInt(0) || | 
 | 5670 |            (element->IsString() && String::cast(element)->LooksValid())); | 
 | 5671 |   } | 
 | 5672 | #endif | 
 | 5673 |   return i; | 
 | 5674 | } | 
 | 5675 |  | 
 | 5676 |  | 
 | 5677 | // Converts a String to JSArray. | 
 | 5678 | // For example, "foo" => ["f", "o", "o"]. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5679 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5680 |   HandleScope scope(isolate); | 
| Shimeng (Simon) Wang | 8a31eba | 2010-12-06 19:01:33 -0800 | [diff] [blame] | 5681 |   ASSERT(args.length() == 2); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5682 |   CONVERT_ARG_CHECKED(String, s, 0); | 
| Shimeng (Simon) Wang | 8a31eba | 2010-12-06 19:01:33 -0800 | [diff] [blame] | 5683 |   CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5684 |  | 
 | 5685 |   s->TryFlatten(); | 
| Shimeng (Simon) Wang | 8a31eba | 2010-12-06 19:01:33 -0800 | [diff] [blame] | 5686 |   const int length = static_cast<int>(Min<uint32_t>(s->length(), limit)); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5687 |  | 
 | 5688 |   Handle<FixedArray> elements; | 
 | 5689 |   if (s->IsFlat() && s->IsAsciiRepresentation()) { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5690 |     Object* obj; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5691 |     { MaybeObject* maybe_obj = | 
 | 5692 |           isolate->heap()->AllocateUninitializedFixedArray(length); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 5693 |       if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 
 | 5694 |     } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5695 |     elements = Handle<FixedArray>(FixedArray::cast(obj), isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5696 |  | 
 | 5697 |     Vector<const char> chars = s->ToAsciiVector(); | 
 | 5698 |     // Note, this will initialize all elements (not only the prefix) | 
 | 5699 |     // to prevent GC from seeing partially initialized array. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5700 |     int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(), | 
 | 5701 |                                                             chars.start(), | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5702 |                                                             *elements, | 
 | 5703 |                                                             length); | 
 | 5704 |  | 
 | 5705 |     for (int i = num_copied_from_cache; i < length; ++i) { | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 5706 |       Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]); | 
 | 5707 |       elements->set(i, *str); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5708 |     } | 
 | 5709 |   } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5710 |     elements = isolate->factory()->NewFixedArray(length); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5711 |     for (int i = 0; i < length; ++i) { | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 5712 |       Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i)); | 
 | 5713 |       elements->set(i, *str); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5714 |     } | 
 | 5715 |   } | 
 | 5716 |  | 
 | 5717 | #ifdef DEBUG | 
 | 5718 |   for (int i = 0; i < length; ++i) { | 
 | 5719 |     ASSERT(String::cast(elements->get(i))->length() == 1); | 
 | 5720 |   } | 
 | 5721 | #endif | 
 | 5722 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5723 |   return *isolate->factory()->NewJSArrayWithElements(elements); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5724 | } | 
 | 5725 |  | 
 | 5726 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5727 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) { | 
| Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 5728 |   NoHandleAllocation ha; | 
 | 5729 |   ASSERT(args.length() == 1); | 
 | 5730 |   CONVERT_CHECKED(String, value, args[0]); | 
 | 5731 |   return value->ToObject(); | 
 | 5732 | } | 
 | 5733 |  | 
 | 5734 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5735 | bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5736 |   unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth]; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5737 |   int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5738 |   return char_length == 0; | 
 | 5739 | } | 
 | 5740 |  | 
 | 5741 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5742 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5743 |   NoHandleAllocation ha; | 
 | 5744 |   ASSERT(args.length() == 1); | 
 | 5745 |  | 
 | 5746 |   Object* number = args[0]; | 
 | 5747 |   RUNTIME_ASSERT(number->IsNumber()); | 
 | 5748 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5749 |   return isolate->heap()->NumberToString(number); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5750 | } | 
 | 5751 |  | 
 | 5752 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5753 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5754 |   NoHandleAllocation ha; | 
 | 5755 |   ASSERT(args.length() == 1); | 
 | 5756 |  | 
 | 5757 |   Object* number = args[0]; | 
 | 5758 |   RUNTIME_ASSERT(number->IsNumber()); | 
 | 5759 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5760 |   return isolate->heap()->NumberToString(number, false); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5761 | } | 
 | 5762 |  | 
 | 5763 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5764 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5765 |   NoHandleAllocation ha; | 
 | 5766 |   ASSERT(args.length() == 1); | 
 | 5767 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5768 |   CONVERT_DOUBLE_CHECKED(number, args[0]); | 
 | 5769 |  | 
 | 5770 |   // We do not include 0 so that we don't have to treat +0 / -0 cases. | 
 | 5771 |   if (number > 0 && number <= Smi::kMaxValue) { | 
 | 5772 |     return Smi::FromInt(static_cast<int>(number)); | 
 | 5773 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5774 |   return isolate->heap()->NumberFromDouble(DoubleToInteger(number)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5775 | } | 
 | 5776 |  | 
 | 5777 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5778 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) { | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 5779 |   NoHandleAllocation ha; | 
 | 5780 |   ASSERT(args.length() == 1); | 
 | 5781 |  | 
 | 5782 |   CONVERT_DOUBLE_CHECKED(number, args[0]); | 
 | 5783 |  | 
 | 5784 |   // We do not include 0 so that we don't have to treat +0 / -0 cases. | 
 | 5785 |   if (number > 0 && number <= Smi::kMaxValue) { | 
 | 5786 |     return Smi::FromInt(static_cast<int>(number)); | 
 | 5787 |   } | 
 | 5788 |  | 
 | 5789 |   double double_value = DoubleToInteger(number); | 
 | 5790 |   // Map both -0 and +0 to +0. | 
 | 5791 |   if (double_value == 0) double_value = 0; | 
 | 5792 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5793 |   return isolate->heap()->NumberFromDouble(double_value); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 5794 | } | 
 | 5795 |  | 
 | 5796 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5797 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5798 |   NoHandleAllocation ha; | 
 | 5799 |   ASSERT(args.length() == 1); | 
 | 5800 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5801 |   CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5802 |   return isolate->heap()->NumberFromUint32(number); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5803 | } | 
 | 5804 |  | 
 | 5805 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5806 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5807 |   NoHandleAllocation ha; | 
 | 5808 |   ASSERT(args.length() == 1); | 
 | 5809 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5810 |   CONVERT_DOUBLE_CHECKED(number, args[0]); | 
 | 5811 |  | 
 | 5812 |   // We do not include 0 so that we don't have to treat +0 / -0 cases. | 
 | 5813 |   if (number > 0 && number <= Smi::kMaxValue) { | 
 | 5814 |     return Smi::FromInt(static_cast<int>(number)); | 
 | 5815 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5816 |   return isolate->heap()->NumberFromInt32(DoubleToInt32(number)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5817 | } | 
 | 5818 |  | 
 | 5819 |  | 
 | 5820 | // Converts a Number to a Smi, if possible. Returns NaN if the number is not | 
 | 5821 | // a small integer. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5822 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5823 |   NoHandleAllocation ha; | 
 | 5824 |   ASSERT(args.length() == 1); | 
 | 5825 |  | 
 | 5826 |   Object* obj = args[0]; | 
 | 5827 |   if (obj->IsSmi()) { | 
 | 5828 |     return obj; | 
 | 5829 |   } | 
 | 5830 |   if (obj->IsHeapNumber()) { | 
 | 5831 |     double value = HeapNumber::cast(obj)->value(); | 
 | 5832 |     int int_value = FastD2I(value); | 
 | 5833 |     if (value == FastI2D(int_value) && Smi::IsValid(int_value)) { | 
 | 5834 |       return Smi::FromInt(int_value); | 
 | 5835 |     } | 
 | 5836 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5837 |   return isolate->heap()->nan_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5838 | } | 
 | 5839 |  | 
 | 5840 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5841 | RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) { | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5842 |   NoHandleAllocation ha; | 
 | 5843 |   ASSERT(args.length() == 0); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5844 |   return isolate->heap()->AllocateHeapNumber(0); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 5845 | } | 
 | 5846 |  | 
 | 5847 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5848 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5849 |   NoHandleAllocation ha; | 
 | 5850 |   ASSERT(args.length() == 2); | 
 | 5851 |  | 
 | 5852 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
 | 5853 |   CONVERT_DOUBLE_CHECKED(y, args[1]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5854 |   return isolate->heap()->NumberFromDouble(x + y); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5855 | } | 
 | 5856 |  | 
 | 5857 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5858 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5859 |   NoHandleAllocation ha; | 
 | 5860 |   ASSERT(args.length() == 2); | 
 | 5861 |  | 
 | 5862 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
 | 5863 |   CONVERT_DOUBLE_CHECKED(y, args[1]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5864 |   return isolate->heap()->NumberFromDouble(x - y); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5865 | } | 
 | 5866 |  | 
 | 5867 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5868 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5869 |   NoHandleAllocation ha; | 
 | 5870 |   ASSERT(args.length() == 2); | 
 | 5871 |  | 
 | 5872 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
 | 5873 |   CONVERT_DOUBLE_CHECKED(y, args[1]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5874 |   return isolate->heap()->NumberFromDouble(x * y); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5875 | } | 
 | 5876 |  | 
 | 5877 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5878 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5879 |   NoHandleAllocation ha; | 
 | 5880 |   ASSERT(args.length() == 1); | 
 | 5881 |  | 
 | 5882 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5883 |   return isolate->heap()->NumberFromDouble(-x); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5884 | } | 
 | 5885 |  | 
 | 5886 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5887 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) { | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 5888 |   NoHandleAllocation ha; | 
 | 5889 |   ASSERT(args.length() == 0); | 
 | 5890 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5891 |   return isolate->heap()->NumberFromDouble(9876543210.0); | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 5892 | } | 
 | 5893 |  | 
 | 5894 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5895 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5896 |   NoHandleAllocation ha; | 
 | 5897 |   ASSERT(args.length() == 2); | 
 | 5898 |  | 
 | 5899 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
 | 5900 |   CONVERT_DOUBLE_CHECKED(y, args[1]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5901 |   return isolate->heap()->NumberFromDouble(x / y); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5902 | } | 
 | 5903 |  | 
 | 5904 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5905 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5906 |   NoHandleAllocation ha; | 
 | 5907 |   ASSERT(args.length() == 2); | 
 | 5908 |  | 
 | 5909 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
 | 5910 |   CONVERT_DOUBLE_CHECKED(y, args[1]); | 
 | 5911 |  | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 5912 |   x = modulo(x, y); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5913 |   // NumberFromDouble may return a Smi instead of a Number object | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5914 |   return isolate->heap()->NumberFromDouble(x); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5915 | } | 
 | 5916 |  | 
 | 5917 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5918 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5919 |   NoHandleAllocation ha; | 
 | 5920 |   ASSERT(args.length() == 2); | 
 | 5921 |   CONVERT_CHECKED(String, str1, args[0]); | 
 | 5922 |   CONVERT_CHECKED(String, str2, args[1]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5923 |   isolate->counters()->string_add_runtime()->Increment(); | 
 | 5924 |   return isolate->heap()->AllocateConsString(str1, str2); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5925 | } | 
 | 5926 |  | 
 | 5927 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 5928 | template <typename sinkchar> | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5929 | static inline void StringBuilderConcatHelper(String* special, | 
 | 5930 |                                              sinkchar* sink, | 
 | 5931 |                                              FixedArray* fixed_array, | 
 | 5932 |                                              int array_length) { | 
 | 5933 |   int position = 0; | 
 | 5934 |   for (int i = 0; i < array_length; i++) { | 
 | 5935 |     Object* element = fixed_array->get(i); | 
 | 5936 |     if (element->IsSmi()) { | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 5937 |       // Smi encoding of position and length. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5938 |       int encoded_slice = Smi::cast(element)->value(); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 5939 |       int pos; | 
 | 5940 |       int len; | 
 | 5941 |       if (encoded_slice > 0) { | 
 | 5942 |         // Position and length encoded in one smi. | 
 | 5943 |         pos = StringBuilderSubstringPosition::decode(encoded_slice); | 
 | 5944 |         len = StringBuilderSubstringLength::decode(encoded_slice); | 
 | 5945 |       } else { | 
 | 5946 |         // Position and length encoded in two smis. | 
 | 5947 |         Object* obj = fixed_array->get(++i); | 
 | 5948 |         ASSERT(obj->IsSmi()); | 
 | 5949 |         pos = Smi::cast(obj)->value(); | 
 | 5950 |         len = -encoded_slice; | 
 | 5951 |       } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5952 |       String::WriteToFlat(special, | 
 | 5953 |                           sink + position, | 
 | 5954 |                           pos, | 
 | 5955 |                           pos + len); | 
 | 5956 |       position += len; | 
 | 5957 |     } else { | 
 | 5958 |       String* string = String::cast(element); | 
 | 5959 |       int element_length = string->length(); | 
 | 5960 |       String::WriteToFlat(string, sink + position, 0, element_length); | 
 | 5961 |       position += element_length; | 
 | 5962 |     } | 
 | 5963 |   } | 
 | 5964 | } | 
 | 5965 |  | 
 | 5966 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 5967 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5968 |   NoHandleAllocation ha; | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 5969 |   ASSERT(args.length() == 3); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5970 |   CONVERT_CHECKED(JSArray, array, args[0]); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 5971 |   if (!args[1]->IsSmi()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5972 |     isolate->context()->mark_out_of_memory(); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 5973 |     return Failure::OutOfMemoryException(); | 
 | 5974 |   } | 
 | 5975 |   int array_length = Smi::cast(args[1])->value(); | 
 | 5976 |   CONVERT_CHECKED(String, special, args[2]); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 5977 |  | 
 | 5978 |   // This assumption is used by the slice encoding in one or two smis. | 
 | 5979 |   ASSERT(Smi::kMaxValue >= String::kMaxLength); | 
 | 5980 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5981 |   int special_length = special->length(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5982 |   if (!array->HasFastElements()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5983 |     return isolate->Throw(isolate->heap()->illegal_argument_symbol()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5984 |   } | 
 | 5985 |   FixedArray* fixed_array = FixedArray::cast(array->elements()); | 
 | 5986 |   if (fixed_array->length() < array_length) { | 
 | 5987 |     array_length = fixed_array->length(); | 
 | 5988 |   } | 
 | 5989 |  | 
 | 5990 |   if (array_length == 0) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 5991 |     return isolate->heap()->empty_string(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5992 |   } else if (array_length == 1) { | 
 | 5993 |     Object* first = fixed_array->get(0); | 
 | 5994 |     if (first->IsString()) return first; | 
 | 5995 |   } | 
 | 5996 |  | 
| Kristian Monsen | 9dcf7e2 | 2010-06-28 14:14:28 +0100 | [diff] [blame] | 5997 |   bool ascii = special->HasOnlyAsciiChars(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 5998 |   int position = 0; | 
 | 5999 |   for (int i = 0; i < array_length; i++) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6000 |     int increment = 0; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6001 |     Object* elt = fixed_array->get(i); | 
 | 6002 |     if (elt->IsSmi()) { | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 6003 |       // Smi encoding of position and length. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6004 |       int smi_value = Smi::cast(elt)->value(); | 
 | 6005 |       int pos; | 
 | 6006 |       int len; | 
 | 6007 |       if (smi_value > 0) { | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 6008 |         // Position and length encoded in one smi. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6009 |         pos = StringBuilderSubstringPosition::decode(smi_value); | 
 | 6010 |         len = StringBuilderSubstringLength::decode(smi_value); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 6011 |       } else { | 
 | 6012 |         // Position and length encoded in two smis. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6013 |         len = -smi_value; | 
 | 6014 |         // Get the position and check that it is a positive smi. | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 6015 |         i++; | 
 | 6016 |         if (i >= array_length) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6017 |           return isolate->Throw(isolate->heap()->illegal_argument_symbol()); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 6018 |         } | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6019 |         Object* next_smi = fixed_array->get(i); | 
 | 6020 |         if (!next_smi->IsSmi()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6021 |           return isolate->Throw(isolate->heap()->illegal_argument_symbol()); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6022 |         } | 
 | 6023 |         pos = Smi::cast(next_smi)->value(); | 
 | 6024 |         if (pos < 0) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6025 |           return isolate->Throw(isolate->heap()->illegal_argument_symbol()); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 6026 |         } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6027 |       } | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6028 |       ASSERT(pos >= 0); | 
 | 6029 |       ASSERT(len >= 0); | 
 | 6030 |       if (pos > special_length || len > special_length - pos) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6031 |         return isolate->Throw(isolate->heap()->illegal_argument_symbol()); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6032 |       } | 
 | 6033 |       increment = len; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6034 |     } else if (elt->IsString()) { | 
 | 6035 |       String* element = String::cast(elt); | 
 | 6036 |       int element_length = element->length(); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 6037 |       increment = element_length; | 
| Kristian Monsen | 9dcf7e2 | 2010-06-28 14:14:28 +0100 | [diff] [blame] | 6038 |       if (ascii && !element->HasOnlyAsciiChars()) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6039 |         ascii = false; | 
 | 6040 |       } | 
 | 6041 |     } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6042 |       return isolate->Throw(isolate->heap()->illegal_argument_symbol()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6043 |     } | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 6044 |     if (increment > String::kMaxLength - position) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6045 |       isolate->context()->mark_out_of_memory(); | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 6046 |       return Failure::OutOfMemoryException(); | 
 | 6047 |     } | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 6048 |     position += increment; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6049 |   } | 
 | 6050 |  | 
 | 6051 |   int length = position; | 
 | 6052 |   Object* object; | 
 | 6053 |  | 
 | 6054 |   if (ascii) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6055 |     { MaybeObject* maybe_object = | 
 | 6056 |           isolate->heap()->AllocateRawAsciiString(length); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 6057 |       if (!maybe_object->ToObject(&object)) return maybe_object; | 
 | 6058 |     } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6059 |     SeqAsciiString* answer = SeqAsciiString::cast(object); | 
 | 6060 |     StringBuilderConcatHelper(special, | 
 | 6061 |                               answer->GetChars(), | 
 | 6062 |                               fixed_array, | 
 | 6063 |                               array_length); | 
 | 6064 |     return answer; | 
 | 6065 |   } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6066 |     { MaybeObject* maybe_object = | 
 | 6067 |           isolate->heap()->AllocateRawTwoByteString(length); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 6068 |       if (!maybe_object->ToObject(&object)) return maybe_object; | 
 | 6069 |     } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6070 |     SeqTwoByteString* answer = SeqTwoByteString::cast(object); | 
 | 6071 |     StringBuilderConcatHelper(special, | 
 | 6072 |                               answer->GetChars(), | 
 | 6073 |                               fixed_array, | 
 | 6074 |                               array_length); | 
 | 6075 |     return answer; | 
 | 6076 |   } | 
 | 6077 | } | 
 | 6078 |  | 
 | 6079 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6080 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 6081 |   NoHandleAllocation ha; | 
 | 6082 |   ASSERT(args.length() == 3); | 
 | 6083 |   CONVERT_CHECKED(JSArray, array, args[0]); | 
 | 6084 |   if (!args[1]->IsSmi()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6085 |     isolate->context()->mark_out_of_memory(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 6086 |     return Failure::OutOfMemoryException(); | 
 | 6087 |   } | 
 | 6088 |   int array_length = Smi::cast(args[1])->value(); | 
 | 6089 |   CONVERT_CHECKED(String, separator, args[2]); | 
 | 6090 |  | 
 | 6091 |   if (!array->HasFastElements()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6092 |     return isolate->Throw(isolate->heap()->illegal_argument_symbol()); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 6093 |   } | 
 | 6094 |   FixedArray* fixed_array = FixedArray::cast(array->elements()); | 
 | 6095 |   if (fixed_array->length() < array_length) { | 
 | 6096 |     array_length = fixed_array->length(); | 
 | 6097 |   } | 
 | 6098 |  | 
 | 6099 |   if (array_length == 0) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6100 |     return isolate->heap()->empty_string(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 6101 |   } else if (array_length == 1) { | 
 | 6102 |     Object* first = fixed_array->get(0); | 
 | 6103 |     if (first->IsString()) return first; | 
 | 6104 |   } | 
 | 6105 |  | 
 | 6106 |   int separator_length = separator->length(); | 
 | 6107 |   int max_nof_separators = | 
 | 6108 |       (String::kMaxLength + separator_length - 1) / separator_length; | 
 | 6109 |   if (max_nof_separators < (array_length - 1)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6110 |       isolate->context()->mark_out_of_memory(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 6111 |       return Failure::OutOfMemoryException(); | 
 | 6112 |   } | 
 | 6113 |   int length = (array_length - 1) * separator_length; | 
 | 6114 |   for (int i = 0; i < array_length; i++) { | 
 | 6115 |     Object* element_obj = fixed_array->get(i); | 
 | 6116 |     if (!element_obj->IsString()) { | 
 | 6117 |       // TODO(1161): handle this case. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6118 |       return isolate->Throw(isolate->heap()->illegal_argument_symbol()); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 6119 |     } | 
 | 6120 |     String* element = String::cast(element_obj); | 
 | 6121 |     int increment = element->length(); | 
 | 6122 |     if (increment > String::kMaxLength - length) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6123 |       isolate->context()->mark_out_of_memory(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 6124 |       return Failure::OutOfMemoryException(); | 
 | 6125 |     } | 
 | 6126 |     length += increment; | 
 | 6127 |   } | 
 | 6128 |  | 
 | 6129 |   Object* object; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6130 |   { MaybeObject* maybe_object = | 
 | 6131 |         isolate->heap()->AllocateRawTwoByteString(length); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 6132 |     if (!maybe_object->ToObject(&object)) return maybe_object; | 
 | 6133 |   } | 
 | 6134 |   SeqTwoByteString* answer = SeqTwoByteString::cast(object); | 
 | 6135 |  | 
 | 6136 |   uc16* sink = answer->GetChars(); | 
 | 6137 | #ifdef DEBUG | 
 | 6138 |   uc16* end = sink + length; | 
 | 6139 | #endif | 
 | 6140 |  | 
 | 6141 |   String* first = String::cast(fixed_array->get(0)); | 
 | 6142 |   int first_length = first->length(); | 
 | 6143 |   String::WriteToFlat(first, sink, 0, first_length); | 
 | 6144 |   sink += first_length; | 
 | 6145 |  | 
 | 6146 |   for (int i = 1; i < array_length; i++) { | 
 | 6147 |     ASSERT(sink + separator_length <= end); | 
 | 6148 |     String::WriteToFlat(separator, sink, 0, separator_length); | 
 | 6149 |     sink += separator_length; | 
 | 6150 |  | 
 | 6151 |     String* element = String::cast(fixed_array->get(i)); | 
 | 6152 |     int element_length = element->length(); | 
 | 6153 |     ASSERT(sink + element_length <= end); | 
 | 6154 |     String::WriteToFlat(element, sink, 0, element_length); | 
 | 6155 |     sink += element_length; | 
 | 6156 |   } | 
 | 6157 |   ASSERT(sink == end); | 
 | 6158 |  | 
 | 6159 |   ASSERT(!answer->HasOnlyAsciiChars());  // Use %_FastAsciiArrayJoin instead. | 
 | 6160 |   return answer; | 
 | 6161 | } | 
 | 6162 |  | 
 | 6163 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6164 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6165 |   NoHandleAllocation ha; | 
 | 6166 |   ASSERT(args.length() == 2); | 
 | 6167 |  | 
 | 6168 |   CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); | 
 | 6169 |   CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6170 |   return isolate->heap()->NumberFromInt32(x | y); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6171 | } | 
 | 6172 |  | 
 | 6173 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6174 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6175 |   NoHandleAllocation ha; | 
 | 6176 |   ASSERT(args.length() == 2); | 
 | 6177 |  | 
 | 6178 |   CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); | 
 | 6179 |   CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6180 |   return isolate->heap()->NumberFromInt32(x & y); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6181 | } | 
 | 6182 |  | 
 | 6183 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6184 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6185 |   NoHandleAllocation ha; | 
 | 6186 |   ASSERT(args.length() == 2); | 
 | 6187 |  | 
 | 6188 |   CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); | 
 | 6189 |   CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6190 |   return isolate->heap()->NumberFromInt32(x ^ y); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6191 | } | 
 | 6192 |  | 
 | 6193 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6194 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6195 |   NoHandleAllocation ha; | 
 | 6196 |   ASSERT(args.length() == 1); | 
 | 6197 |  | 
 | 6198 |   CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6199 |   return isolate->heap()->NumberFromInt32(~x); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6200 | } | 
 | 6201 |  | 
 | 6202 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6203 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6204 |   NoHandleAllocation ha; | 
 | 6205 |   ASSERT(args.length() == 2); | 
 | 6206 |  | 
 | 6207 |   CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); | 
 | 6208 |   CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6209 |   return isolate->heap()->NumberFromInt32(x << (y & 0x1f)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6210 | } | 
 | 6211 |  | 
 | 6212 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6213 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6214 |   NoHandleAllocation ha; | 
 | 6215 |   ASSERT(args.length() == 2); | 
 | 6216 |  | 
 | 6217 |   CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]); | 
 | 6218 |   CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6219 |   return isolate->heap()->NumberFromUint32(x >> (y & 0x1f)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6220 | } | 
 | 6221 |  | 
 | 6222 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6223 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6224 |   NoHandleAllocation ha; | 
 | 6225 |   ASSERT(args.length() == 2); | 
 | 6226 |  | 
 | 6227 |   CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); | 
 | 6228 |   CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6229 |   return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6230 | } | 
 | 6231 |  | 
 | 6232 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6233 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6234 |   NoHandleAllocation ha; | 
 | 6235 |   ASSERT(args.length() == 2); | 
 | 6236 |  | 
 | 6237 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
 | 6238 |   CONVERT_DOUBLE_CHECKED(y, args[1]); | 
 | 6239 |   if (isnan(x)) return Smi::FromInt(NOT_EQUAL); | 
 | 6240 |   if (isnan(y)) return Smi::FromInt(NOT_EQUAL); | 
 | 6241 |   if (x == y) return Smi::FromInt(EQUAL); | 
 | 6242 |   Object* result; | 
 | 6243 |   if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) { | 
 | 6244 |     result = Smi::FromInt(EQUAL); | 
 | 6245 |   } else { | 
 | 6246 |     result = Smi::FromInt(NOT_EQUAL); | 
 | 6247 |   } | 
 | 6248 |   return result; | 
 | 6249 | } | 
 | 6250 |  | 
 | 6251 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6252 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6253 |   NoHandleAllocation ha; | 
 | 6254 |   ASSERT(args.length() == 2); | 
 | 6255 |  | 
 | 6256 |   CONVERT_CHECKED(String, x, args[0]); | 
 | 6257 |   CONVERT_CHECKED(String, y, args[1]); | 
 | 6258 |  | 
 | 6259 |   bool not_equal = !x->Equals(y); | 
 | 6260 |   // This is slightly convoluted because the value that signifies | 
 | 6261 |   // equality is 0 and inequality is 1 so we have to negate the result | 
 | 6262 |   // from String::Equals. | 
 | 6263 |   ASSERT(not_equal == 0 || not_equal == 1); | 
 | 6264 |   STATIC_CHECK(EQUAL == 0); | 
 | 6265 |   STATIC_CHECK(NOT_EQUAL == 1); | 
 | 6266 |   return Smi::FromInt(not_equal); | 
 | 6267 | } | 
 | 6268 |  | 
 | 6269 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6270 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6271 |   NoHandleAllocation ha; | 
 | 6272 |   ASSERT(args.length() == 3); | 
 | 6273 |  | 
 | 6274 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
 | 6275 |   CONVERT_DOUBLE_CHECKED(y, args[1]); | 
 | 6276 |   if (isnan(x) || isnan(y)) return args[2]; | 
 | 6277 |   if (x == y) return Smi::FromInt(EQUAL); | 
 | 6278 |   if (isless(x, y)) return Smi::FromInt(LESS); | 
 | 6279 |   return Smi::FromInt(GREATER); | 
 | 6280 | } | 
 | 6281 |  | 
 | 6282 |  | 
 | 6283 | // Compare two Smis as if they were converted to strings and then | 
 | 6284 | // compared lexicographically. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6285 | RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6286 |   NoHandleAllocation ha; | 
 | 6287 |   ASSERT(args.length() == 2); | 
 | 6288 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6289 |   // Extract the integer values from the Smis. | 
 | 6290 |   CONVERT_CHECKED(Smi, x, args[0]); | 
 | 6291 |   CONVERT_CHECKED(Smi, y, args[1]); | 
 | 6292 |   int x_value = x->value(); | 
 | 6293 |   int y_value = y->value(); | 
 | 6294 |  | 
 | 6295 |   // If the integers are equal so are the string representations. | 
 | 6296 |   if (x_value == y_value) return Smi::FromInt(EQUAL); | 
 | 6297 |  | 
 | 6298 |   // If one of the integers are zero the normal integer order is the | 
 | 6299 |   // same as the lexicographic order of the string representations. | 
 | 6300 |   if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value); | 
 | 6301 |  | 
 | 6302 |   // If only one of the integers is negative the negative number is | 
 | 6303 |   // smallest because the char code of '-' is less than the char code | 
 | 6304 |   // of any digit.  Otherwise, we make both values positive. | 
 | 6305 |   if (x_value < 0 || y_value < 0) { | 
 | 6306 |     if (y_value >= 0) return Smi::FromInt(LESS); | 
 | 6307 |     if (x_value >= 0) return Smi::FromInt(GREATER); | 
 | 6308 |     x_value = -x_value; | 
 | 6309 |     y_value = -y_value; | 
 | 6310 |   } | 
 | 6311 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6312 |   // Arrays for the individual characters of the two Smis.  Smis are | 
 | 6313 |   // 31 bit integers and 10 decimal digits are therefore enough. | 
 | 6314 |   // TODO(isolates): maybe we should simply allocate 20 bytes on the stack. | 
 | 6315 |   int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms(); | 
 | 6316 |   int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms(); | 
 | 6317 |  | 
 | 6318 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6319 |   // Convert the integers to arrays of their decimal digits. | 
 | 6320 |   int x_index = 0; | 
 | 6321 |   int y_index = 0; | 
 | 6322 |   while (x_value > 0) { | 
 | 6323 |     x_elms[x_index++] = x_value % 10; | 
 | 6324 |     x_value /= 10; | 
 | 6325 |   } | 
 | 6326 |   while (y_value > 0) { | 
 | 6327 |     y_elms[y_index++] = y_value % 10; | 
 | 6328 |     y_value /= 10; | 
 | 6329 |   } | 
 | 6330 |  | 
 | 6331 |   // Loop through the arrays of decimal digits finding the first place | 
 | 6332 |   // where they differ. | 
 | 6333 |   while (--x_index >= 0 && --y_index >= 0) { | 
 | 6334 |     int diff = x_elms[x_index] - y_elms[y_index]; | 
 | 6335 |     if (diff != 0) return Smi::FromInt(diff); | 
 | 6336 |   } | 
 | 6337 |  | 
 | 6338 |   // If one array is a suffix of the other array, the longest array is | 
 | 6339 |   // the representation of the largest of the Smis in the | 
 | 6340 |   // lexicographic ordering. | 
 | 6341 |   return Smi::FromInt(x_index - y_index); | 
 | 6342 | } | 
 | 6343 |  | 
 | 6344 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6345 | static Object* StringInputBufferCompare(RuntimeState* state, | 
 | 6346 |                                         String* x, | 
 | 6347 |                                         String* y) { | 
 | 6348 |   StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx(); | 
 | 6349 |   StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6350 |   bufx.Reset(x); | 
 | 6351 |   bufy.Reset(y); | 
 | 6352 |   while (bufx.has_more() && bufy.has_more()) { | 
 | 6353 |     int d = bufx.GetNext() - bufy.GetNext(); | 
 | 6354 |     if (d < 0) return Smi::FromInt(LESS); | 
 | 6355 |     else if (d > 0) return Smi::FromInt(GREATER); | 
 | 6356 |   } | 
 | 6357 |  | 
 | 6358 |   // x is (non-trivial) prefix of y: | 
 | 6359 |   if (bufy.has_more()) return Smi::FromInt(LESS); | 
 | 6360 |   // y is prefix of x: | 
 | 6361 |   return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL); | 
 | 6362 | } | 
 | 6363 |  | 
 | 6364 |  | 
 | 6365 | static Object* FlatStringCompare(String* x, String* y) { | 
 | 6366 |   ASSERT(x->IsFlat()); | 
 | 6367 |   ASSERT(y->IsFlat()); | 
 | 6368 |   Object* equal_prefix_result = Smi::FromInt(EQUAL); | 
 | 6369 |   int prefix_length = x->length(); | 
 | 6370 |   if (y->length() < prefix_length) { | 
 | 6371 |     prefix_length = y->length(); | 
 | 6372 |     equal_prefix_result = Smi::FromInt(GREATER); | 
 | 6373 |   } else if (y->length() > prefix_length) { | 
 | 6374 |     equal_prefix_result = Smi::FromInt(LESS); | 
 | 6375 |   } | 
 | 6376 |   int r; | 
 | 6377 |   if (x->IsAsciiRepresentation()) { | 
 | 6378 |     Vector<const char> x_chars = x->ToAsciiVector(); | 
 | 6379 |     if (y->IsAsciiRepresentation()) { | 
 | 6380 |       Vector<const char> y_chars = y->ToAsciiVector(); | 
 | 6381 |       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); | 
 | 6382 |     } else { | 
 | 6383 |       Vector<const uc16> y_chars = y->ToUC16Vector(); | 
 | 6384 |       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); | 
 | 6385 |     } | 
 | 6386 |   } else { | 
 | 6387 |     Vector<const uc16> x_chars = x->ToUC16Vector(); | 
 | 6388 |     if (y->IsAsciiRepresentation()) { | 
 | 6389 |       Vector<const char> y_chars = y->ToAsciiVector(); | 
 | 6390 |       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); | 
 | 6391 |     } else { | 
 | 6392 |       Vector<const uc16> y_chars = y->ToUC16Vector(); | 
 | 6393 |       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); | 
 | 6394 |     } | 
 | 6395 |   } | 
 | 6396 |   Object* result; | 
 | 6397 |   if (r == 0) { | 
 | 6398 |     result = equal_prefix_result; | 
 | 6399 |   } else { | 
 | 6400 |     result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER); | 
 | 6401 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6402 |   ASSERT(result == | 
 | 6403 |       StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y)); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6404 |   return result; | 
 | 6405 | } | 
 | 6406 |  | 
 | 6407 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6408 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6409 |   NoHandleAllocation ha; | 
 | 6410 |   ASSERT(args.length() == 2); | 
 | 6411 |  | 
 | 6412 |   CONVERT_CHECKED(String, x, args[0]); | 
 | 6413 |   CONVERT_CHECKED(String, y, args[1]); | 
 | 6414 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6415 |   isolate->counters()->string_compare_runtime()->Increment(); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 6416 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6417 |   // A few fast case tests before we flatten. | 
 | 6418 |   if (x == y) return Smi::FromInt(EQUAL); | 
 | 6419 |   if (y->length() == 0) { | 
 | 6420 |     if (x->length() == 0) return Smi::FromInt(EQUAL); | 
 | 6421 |     return Smi::FromInt(GREATER); | 
 | 6422 |   } else if (x->length() == 0) { | 
 | 6423 |     return Smi::FromInt(LESS); | 
 | 6424 |   } | 
 | 6425 |  | 
 | 6426 |   int d = x->Get(0) - y->Get(0); | 
 | 6427 |   if (d < 0) return Smi::FromInt(LESS); | 
 | 6428 |   else if (d > 0) return Smi::FromInt(GREATER); | 
 | 6429 |  | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 6430 |   Object* obj; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6431 |   { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 6432 |     if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 
 | 6433 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6434 |   { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 6435 |     if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 
 | 6436 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6437 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6438 |   return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y) | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6439 |       : StringInputBufferCompare(isolate->runtime_state(), x, y); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6440 | } | 
 | 6441 |  | 
 | 6442 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6443 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6444 |   NoHandleAllocation ha; | 
 | 6445 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6446 |   isolate->counters()->math_acos()->Increment(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6447 |  | 
 | 6448 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6449 |   return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6450 | } | 
 | 6451 |  | 
 | 6452 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6453 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6454 |   NoHandleAllocation ha; | 
 | 6455 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6456 |   isolate->counters()->math_asin()->Increment(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6457 |  | 
 | 6458 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6459 |   return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6460 | } | 
 | 6461 |  | 
 | 6462 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6463 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6464 |   NoHandleAllocation ha; | 
 | 6465 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6466 |   isolate->counters()->math_atan()->Increment(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6467 |  | 
 | 6468 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6469 |   return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6470 | } | 
 | 6471 |  | 
 | 6472 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6473 | static const double kPiDividedBy4 = 0.78539816339744830962; | 
 | 6474 |  | 
 | 6475 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6476 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6477 |   NoHandleAllocation ha; | 
 | 6478 |   ASSERT(args.length() == 2); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6479 |   isolate->counters()->math_atan2()->Increment(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6480 |  | 
 | 6481 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
 | 6482 |   CONVERT_DOUBLE_CHECKED(y, args[1]); | 
 | 6483 |   double result; | 
 | 6484 |   if (isinf(x) && isinf(y)) { | 
 | 6485 |     // Make sure that the result in case of two infinite arguments | 
 | 6486 |     // is a multiple of Pi / 4. The sign of the result is determined | 
 | 6487 |     // by the first argument (x) and the sign of the second argument | 
 | 6488 |     // determines the multiplier: one or three. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6489 |     int multiplier = (x < 0) ? -1 : 1; | 
 | 6490 |     if (y < 0) multiplier *= 3; | 
 | 6491 |     result = multiplier * kPiDividedBy4; | 
 | 6492 |   } else { | 
 | 6493 |     result = atan2(x, y); | 
 | 6494 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6495 |   return isolate->heap()->AllocateHeapNumber(result); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6496 | } | 
 | 6497 |  | 
 | 6498 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6499 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6500 |   NoHandleAllocation ha; | 
 | 6501 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6502 |   isolate->counters()->math_ceil()->Increment(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6503 |  | 
 | 6504 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6505 |   return isolate->heap()->NumberFromDouble(ceiling(x)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6506 | } | 
 | 6507 |  | 
 | 6508 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6509 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6510 |   NoHandleAllocation ha; | 
 | 6511 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6512 |   isolate->counters()->math_cos()->Increment(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6513 |  | 
 | 6514 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6515 |   return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6516 | } | 
 | 6517 |  | 
 | 6518 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6519 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6520 |   NoHandleAllocation ha; | 
 | 6521 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6522 |   isolate->counters()->math_exp()->Increment(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6523 |  | 
 | 6524 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6525 |   return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6526 | } | 
 | 6527 |  | 
 | 6528 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6529 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6530 |   NoHandleAllocation ha; | 
 | 6531 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6532 |   isolate->counters()->math_floor()->Increment(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6533 |  | 
 | 6534 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6535 |   return isolate->heap()->NumberFromDouble(floor(x)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6536 | } | 
 | 6537 |  | 
 | 6538 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6539 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6540 |   NoHandleAllocation ha; | 
 | 6541 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6542 |   isolate->counters()->math_log()->Increment(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6543 |  | 
 | 6544 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6545 |   return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6546 | } | 
 | 6547 |  | 
 | 6548 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6549 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6550 |   NoHandleAllocation ha; | 
 | 6551 |   ASSERT(args.length() == 2); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6552 |   isolate->counters()->math_pow()->Increment(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6553 |  | 
 | 6554 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
 | 6555 |  | 
 | 6556 |   // If the second argument is a smi, it is much faster to call the | 
 | 6557 |   // custom powi() function than the generic pow(). | 
 | 6558 |   if (args[1]->IsSmi()) { | 
 | 6559 |     int y = Smi::cast(args[1])->value(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6560 |     return isolate->heap()->NumberFromDouble(power_double_int(x, y)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6561 |   } | 
 | 6562 |  | 
 | 6563 |   CONVERT_DOUBLE_CHECKED(y, args[1]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6564 |   return isolate->heap()->AllocateHeapNumber(power_double_double(x, y)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6565 | } | 
 | 6566 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6567 | // Fast version of Math.pow if we know that y is not an integer and | 
 | 6568 | // y is not -0.5 or 0.5. Used as slowcase from codegen. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6569 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6570 |   NoHandleAllocation ha; | 
 | 6571 |   ASSERT(args.length() == 2); | 
 | 6572 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
 | 6573 |   CONVERT_DOUBLE_CHECKED(y, args[1]); | 
 | 6574 |   if (y == 0) { | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 6575 |     return Smi::FromInt(1); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6576 |   } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6577 |     return isolate->heap()->nan_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6578 |   } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6579 |     return isolate->heap()->AllocateHeapNumber(pow(x, y)); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6580 |   } | 
 | 6581 | } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6582 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6583 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6584 | RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6585 |   NoHandleAllocation ha; | 
 | 6586 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6587 |   isolate->counters()->math_round()->Increment(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6588 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6589 |   if (!args[0]->IsHeapNumber()) { | 
 | 6590 |     // Must be smi. Return the argument unchanged for all the other types | 
 | 6591 |     // to make fuzz-natives test happy. | 
 | 6592 |     return args[0]; | 
 | 6593 |   } | 
 | 6594 |  | 
 | 6595 |   HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]); | 
 | 6596 |  | 
 | 6597 |   double value = number->value(); | 
 | 6598 |   int exponent = number->get_exponent(); | 
 | 6599 |   int sign = number->get_sign(); | 
 | 6600 |  | 
| Steve Block | 053d10c | 2011-06-13 19:13:29 +0100 | [diff] [blame] | 6601 |   // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and | 
 | 6602 |   // should be rounded to 2^30, which is not smi. | 
 | 6603 |   if (!sign && exponent <= kSmiValueSize - 3) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6604 |     return Smi::FromInt(static_cast<int>(value + 0.5)); | 
 | 6605 |   } | 
 | 6606 |  | 
 | 6607 |   // If the magnitude is big enough, there's no place for fraction part. If we | 
 | 6608 |   // try to add 0.5 to this number, 1.0 will be added instead. | 
 | 6609 |   if (exponent >= 52) { | 
 | 6610 |     return number; | 
 | 6611 |   } | 
 | 6612 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6613 |   if (sign && value >= -0.5) return isolate->heap()->minus_zero_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6614 |  | 
 | 6615 |   // Do not call NumberFromDouble() to avoid extra checks. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6616 |   return isolate->heap()->AllocateHeapNumber(floor(value + 0.5)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6617 | } | 
 | 6618 |  | 
 | 6619 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6620 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6621 |   NoHandleAllocation ha; | 
 | 6622 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6623 |   isolate->counters()->math_sin()->Increment(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6624 |  | 
 | 6625 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6626 |   return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6627 | } | 
 | 6628 |  | 
 | 6629 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6630 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6631 |   NoHandleAllocation ha; | 
 | 6632 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6633 |   isolate->counters()->math_sqrt()->Increment(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6634 |  | 
 | 6635 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6636 |   return isolate->heap()->AllocateHeapNumber(sqrt(x)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6637 | } | 
 | 6638 |  | 
 | 6639 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6640 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6641 |   NoHandleAllocation ha; | 
 | 6642 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6643 |   isolate->counters()->math_tan()->Increment(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6644 |  | 
 | 6645 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 6646 |   return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 6647 | } | 
 | 6648 |  | 
 | 6649 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6650 | static int MakeDay(int year, int month, int day) { | 
 | 6651 |   static const int day_from_month[] = {0, 31, 59, 90, 120, 151, | 
 | 6652 |                                        181, 212, 243, 273, 304, 334}; | 
 | 6653 |   static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152, | 
 | 6654 |                                             182, 213, 244, 274, 305, 335}; | 
 | 6655 |  | 
 | 6656 |   year += month / 12; | 
 | 6657 |   month %= 12; | 
 | 6658 |   if (month < 0) { | 
 | 6659 |     year--; | 
 | 6660 |     month += 12; | 
 | 6661 |   } | 
 | 6662 |  | 
 | 6663 |   ASSERT(month >= 0); | 
 | 6664 |   ASSERT(month < 12); | 
 | 6665 |  | 
 | 6666 |   // year_delta is an arbitrary number such that: | 
 | 6667 |   // a) year_delta = -1 (mod 400) | 
 | 6668 |   // b) year + year_delta > 0 for years in the range defined by | 
 | 6669 |   //    ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of | 
 | 6670 |   //    Jan 1 1970. This is required so that we don't run into integer | 
 | 6671 |   //    division of negative numbers. | 
 | 6672 |   // c) there shouldn't be an overflow for 32-bit integers in the following | 
 | 6673 |   //    operations. | 
 | 6674 |   static const int year_delta = 399999; | 
 | 6675 |   static const int base_day = 365 * (1970 + year_delta) + | 
 | 6676 |                               (1970 + year_delta) / 4 - | 
 | 6677 |                               (1970 + year_delta) / 100 + | 
 | 6678 |                               (1970 + year_delta) / 400; | 
 | 6679 |  | 
 | 6680 |   int year1 = year + year_delta; | 
 | 6681 |   int day_from_year = 365 * year1 + | 
 | 6682 |                       year1 / 4 - | 
 | 6683 |                       year1 / 100 + | 
 | 6684 |                       year1 / 400 - | 
 | 6685 |                       base_day; | 
 | 6686 |  | 
 | 6687 |   if (year % 4 || (year % 100 == 0 && year % 400 != 0)) { | 
 | 6688 |     return day_from_year + day_from_month[month] + day - 1; | 
 | 6689 |   } | 
 | 6690 |  | 
 | 6691 |   return day_from_year + day_from_month_leap[month] + day - 1; | 
 | 6692 | } | 
 | 6693 |  | 
 | 6694 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6695 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6696 |   NoHandleAllocation ha; | 
 | 6697 |   ASSERT(args.length() == 3); | 
 | 6698 |  | 
 | 6699 |   CONVERT_SMI_CHECKED(year, args[0]); | 
 | 6700 |   CONVERT_SMI_CHECKED(month, args[1]); | 
 | 6701 |   CONVERT_SMI_CHECKED(date, args[2]); | 
 | 6702 |  | 
 | 6703 |   return Smi::FromInt(MakeDay(year, month, date)); | 
 | 6704 | } | 
 | 6705 |  | 
 | 6706 |  | 
 | 6707 | static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1}; | 
 | 6708 | static const int kDaysIn4Years = 4 * 365 + 1; | 
 | 6709 | static const int kDaysIn100Years = 25 * kDaysIn4Years - 1; | 
 | 6710 | static const int kDaysIn400Years = 4 * kDaysIn100Years + 1; | 
 | 6711 | static const int kDays1970to2000 = 30 * 365 + 7; | 
 | 6712 | static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years - | 
 | 6713 |                                kDays1970to2000; | 
 | 6714 | static const int kYearsOffset = 400000; | 
 | 6715 |  | 
 | 6716 | static const char kDayInYear[] = { | 
 | 6717 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6718 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6719 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6720 |       22, 23, 24, 25, 26, 27, 28, | 
 | 6721 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6722 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6723 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6724 |       22, 23, 24, 25, 26, 27, 28, 29, 30, | 
 | 6725 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6726 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6727 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6728 |       22, 23, 24, 25, 26, 27, 28, 29, 30, | 
 | 6729 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6730 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6731 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6732 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6733 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6734 |       22, 23, 24, 25, 26, 27, 28, 29, 30, | 
 | 6735 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6736 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6737 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6738 |       22, 23, 24, 25, 26, 27, 28, 29, 30, | 
 | 6739 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6740 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6741 |  | 
 | 6742 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6743 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6744 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6745 |       22, 23, 24, 25, 26, 27, 28, | 
 | 6746 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6747 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6748 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6749 |       22, 23, 24, 25, 26, 27, 28, 29, 30, | 
 | 6750 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6751 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6752 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6753 |       22, 23, 24, 25, 26, 27, 28, 29, 30, | 
 | 6754 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6755 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6756 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6757 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6758 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6759 |       22, 23, 24, 25, 26, 27, 28, 29, 30, | 
 | 6760 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6761 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6762 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6763 |       22, 23, 24, 25, 26, 27, 28, 29, 30, | 
 | 6764 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6765 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6766 |  | 
 | 6767 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6768 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6769 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6770 |       22, 23, 24, 25, 26, 27, 28, 29, | 
 | 6771 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6772 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6773 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6774 |       22, 23, 24, 25, 26, 27, 28, 29, 30, | 
 | 6775 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6776 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6777 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6778 |       22, 23, 24, 25, 26, 27, 28, 29, 30, | 
 | 6779 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6780 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6781 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6782 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6783 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6784 |       22, 23, 24, 25, 26, 27, 28, 29, 30, | 
 | 6785 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6786 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6787 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6788 |       22, 23, 24, 25, 26, 27, 28, 29, 30, | 
 | 6789 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6790 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6791 |  | 
 | 6792 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6793 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6794 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6795 |       22, 23, 24, 25, 26, 27, 28, | 
 | 6796 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6797 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6798 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6799 |       22, 23, 24, 25, 26, 27, 28, 29, 30, | 
 | 6800 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6801 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6802 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6803 |       22, 23, 24, 25, 26, 27, 28, 29, 30, | 
 | 6804 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6805 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6806 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6807 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6808 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6809 |       22, 23, 24, 25, 26, 27, 28, 29, 30, | 
 | 6810 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6811 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 
 | 6812 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6813 |       22, 23, 24, 25, 26, 27, 28, 29, 30, | 
 | 6814 |       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | 
 | 6815 |       22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; | 
 | 6816 |  | 
 | 6817 | static const char kMonthInYear[] = { | 
 | 6818 |       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
 | 6819 |       0, 0, 0, 0, 0, 0, | 
 | 6820 |       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 
 | 6821 |       1, 1, 1, | 
 | 6822 |       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | 
 | 6823 |       2, 2, 2, 2, 2, 2, | 
 | 6824 |       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | 
 | 6825 |       3, 3, 3, 3, 3, | 
 | 6826 |       4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, | 
 | 6827 |       4, 4, 4, 4, 4, 4, | 
 | 6828 |       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | 
 | 6829 |       5, 5, 5, 5, 5, | 
 | 6830 |       6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | 
 | 6831 |       6, 6, 6, 6, 6, 6, | 
 | 6832 |       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | 
 | 6833 |       7, 7, 7, 7, 7, 7, | 
 | 6834 |       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | 
 | 6835 |       8, 8, 8, 8, 8, | 
 | 6836 |       9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, | 
 | 6837 |       9, 9, 9, 9, 9, 9, | 
 | 6838 |       10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | 
 | 6839 |       10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | 
 | 6840 |       11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, | 
 | 6841 |       11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, | 
 | 6842 |  | 
 | 6843 |       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
 | 6844 |       0, 0, 0, 0, 0, 0, | 
 | 6845 |       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 
 | 6846 |       1, 1, 1, | 
 | 6847 |       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | 
 | 6848 |       2, 2, 2, 2, 2, 2, | 
 | 6849 |       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | 
 | 6850 |       3, 3, 3, 3, 3, | 
 | 6851 |       4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, | 
 | 6852 |       4, 4, 4, 4, 4, 4, | 
 | 6853 |       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | 
 | 6854 |       5, 5, 5, 5, 5, | 
 | 6855 |       6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | 
 | 6856 |       6, 6, 6, 6, 6, 6, | 
 | 6857 |       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | 
 | 6858 |       7, 7, 7, 7, 7, 7, | 
 | 6859 |       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | 
 | 6860 |       8, 8, 8, 8, 8, | 
 | 6861 |       9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, | 
 | 6862 |       9, 9, 9, 9, 9, 9, | 
 | 6863 |       10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | 
 | 6864 |       10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | 
 | 6865 |       11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, | 
 | 6866 |       11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, | 
 | 6867 |  | 
 | 6868 |       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
 | 6869 |       0, 0, 0, 0, 0, 0, | 
 | 6870 |       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 
 | 6871 |       1, 1, 1, 1, | 
 | 6872 |       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | 
 | 6873 |       2, 2, 2, 2, 2, 2, | 
 | 6874 |       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | 
 | 6875 |       3, 3, 3, 3, 3, | 
 | 6876 |       4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, | 
 | 6877 |       4, 4, 4, 4, 4, 4, | 
 | 6878 |       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | 
 | 6879 |       5, 5, 5, 5, 5, | 
 | 6880 |       6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | 
 | 6881 |       6, 6, 6, 6, 6, 6, | 
 | 6882 |       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | 
 | 6883 |       7, 7, 7, 7, 7, 7, | 
 | 6884 |       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | 
 | 6885 |       8, 8, 8, 8, 8, | 
 | 6886 |       9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, | 
 | 6887 |       9, 9, 9, 9, 9, 9, | 
 | 6888 |       10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | 
 | 6889 |       10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | 
 | 6890 |       11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, | 
 | 6891 |       11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, | 
 | 6892 |  | 
 | 6893 |       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
 | 6894 |       0, 0, 0, 0, 0, 0, | 
 | 6895 |       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 
 | 6896 |       1, 1, 1, | 
 | 6897 |       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | 
 | 6898 |       2, 2, 2, 2, 2, 2, | 
 | 6899 |       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | 
 | 6900 |       3, 3, 3, 3, 3, | 
 | 6901 |       4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, | 
 | 6902 |       4, 4, 4, 4, 4, 4, | 
 | 6903 |       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | 
 | 6904 |       5, 5, 5, 5, 5, | 
 | 6905 |       6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | 
 | 6906 |       6, 6, 6, 6, 6, 6, | 
 | 6907 |       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | 
 | 6908 |       7, 7, 7, 7, 7, 7, | 
 | 6909 |       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | 
 | 6910 |       8, 8, 8, 8, 8, | 
 | 6911 |       9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, | 
 | 6912 |       9, 9, 9, 9, 9, 9, | 
 | 6913 |       10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | 
 | 6914 |       10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | 
 | 6915 |       11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, | 
 | 6916 |       11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11}; | 
 | 6917 |  | 
 | 6918 |  | 
 | 6919 | // This function works for dates from 1970 to 2099. | 
 | 6920 | static inline void DateYMDFromTimeAfter1970(int date, | 
 | 6921 |                                             int& year, int& month, int& day) { | 
 | 6922 | #ifdef DEBUG | 
 | 6923 |   int save_date = date;  // Need this for ASSERT in the end. | 
 | 6924 | #endif | 
 | 6925 |  | 
 | 6926 |   year = 1970 + (4 * date + 2) / kDaysIn4Years; | 
 | 6927 |   date %= kDaysIn4Years; | 
 | 6928 |  | 
 | 6929 |   month = kMonthInYear[date]; | 
 | 6930 |   day = kDayInYear[date]; | 
 | 6931 |  | 
 | 6932 |   ASSERT(MakeDay(year, month, day) == save_date); | 
 | 6933 | } | 
 | 6934 |  | 
 | 6935 |  | 
 | 6936 | static inline void DateYMDFromTimeSlow(int date, | 
 | 6937 |                                        int& year, int& month, int& day) { | 
 | 6938 | #ifdef DEBUG | 
 | 6939 |   int save_date = date;  // Need this for ASSERT in the end. | 
 | 6940 | #endif | 
 | 6941 |  | 
 | 6942 |   date += kDaysOffset; | 
 | 6943 |   year = 400 * (date / kDaysIn400Years) - kYearsOffset; | 
 | 6944 |   date %= kDaysIn400Years; | 
 | 6945 |  | 
 | 6946 |   ASSERT(MakeDay(year, 0, 1) + date == save_date); | 
 | 6947 |  | 
 | 6948 |   date--; | 
 | 6949 |   int yd1 = date / kDaysIn100Years; | 
 | 6950 |   date %= kDaysIn100Years; | 
 | 6951 |   year += 100 * yd1; | 
 | 6952 |  | 
 | 6953 |   date++; | 
 | 6954 |   int yd2 = date / kDaysIn4Years; | 
 | 6955 |   date %= kDaysIn4Years; | 
 | 6956 |   year += 4 * yd2; | 
 | 6957 |  | 
 | 6958 |   date--; | 
 | 6959 |   int yd3 = date / 365; | 
 | 6960 |   date %= 365; | 
 | 6961 |   year += yd3; | 
 | 6962 |  | 
 | 6963 |   bool is_leap = (!yd1 || yd2) && !yd3; | 
 | 6964 |  | 
 | 6965 |   ASSERT(date >= -1); | 
 | 6966 |   ASSERT(is_leap || (date >= 0)); | 
 | 6967 |   ASSERT((date < 365) || (is_leap && (date < 366))); | 
 | 6968 |   ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0)))); | 
 | 6969 |   ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date)); | 
 | 6970 |   ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date)); | 
 | 6971 |  | 
 | 6972 |   if (is_leap) { | 
 | 6973 |     day = kDayInYear[2*365 + 1 + date]; | 
 | 6974 |     month = kMonthInYear[2*365 + 1 + date]; | 
 | 6975 |   } else { | 
 | 6976 |     day = kDayInYear[date]; | 
 | 6977 |     month = kMonthInYear[date]; | 
 | 6978 |   } | 
 | 6979 |  | 
 | 6980 |   ASSERT(MakeDay(year, month, day) == save_date); | 
 | 6981 | } | 
 | 6982 |  | 
 | 6983 |  | 
 | 6984 | static inline void DateYMDFromTime(int date, | 
 | 6985 |                                    int& year, int& month, int& day) { | 
 | 6986 |   if (date >= 0 && date < 32 * kDaysIn4Years) { | 
 | 6987 |     DateYMDFromTimeAfter1970(date, year, month, day); | 
 | 6988 |   } else { | 
 | 6989 |     DateYMDFromTimeSlow(date, year, month, day); | 
 | 6990 |   } | 
 | 6991 | } | 
 | 6992 |  | 
 | 6993 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 6994 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 6995 |   NoHandleAllocation ha; | 
 | 6996 |   ASSERT(args.length() == 2); | 
 | 6997 |  | 
 | 6998 |   CONVERT_DOUBLE_CHECKED(t, args[0]); | 
 | 6999 |   CONVERT_CHECKED(JSArray, res_array, args[1]); | 
 | 7000 |  | 
 | 7001 |   int year, month, day; | 
 | 7002 |   DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day); | 
 | 7003 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7004 |   RUNTIME_ASSERT(res_array->elements()->map() == | 
 | 7005 |                  isolate->heap()->fixed_array_map()); | 
| Iain Merrick | 7568138 | 2010-08-19 15:07:18 +0100 | [diff] [blame] | 7006 |   FixedArray* elms = FixedArray::cast(res_array->elements()); | 
 | 7007 |   RUNTIME_ASSERT(elms->length() == 3); | 
 | 7008 |  | 
 | 7009 |   elms->set(0, Smi::FromInt(year)); | 
 | 7010 |   elms->set(1, Smi::FromInt(month)); | 
 | 7011 |   elms->set(2, Smi::FromInt(day)); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 7012 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7013 |   return isolate->heap()->undefined_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 7014 | } | 
 | 7015 |  | 
 | 7016 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7017 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7018 |   NoHandleAllocation ha; | 
 | 7019 |   ASSERT(args.length() == 3); | 
 | 7020 |  | 
 | 7021 |   JSFunction* callee = JSFunction::cast(args[0]); | 
 | 7022 |   Object** parameters = reinterpret_cast<Object**>(args[1]); | 
 | 7023 |   const int length = Smi::cast(args[2])->value(); | 
 | 7024 |  | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7025 |   Object* result; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7026 |   { MaybeObject* maybe_result = | 
 | 7027 |         isolate->heap()->AllocateArgumentsObject(callee, length); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7028 |     if (!maybe_result->ToObject(&result)) return maybe_result; | 
 | 7029 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7030 |   // Allocate the elements if needed. | 
 | 7031 |   if (length > 0) { | 
 | 7032 |     // Allocate the fixed array. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7033 |     Object* obj; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7034 |     { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7035 |       if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 
 | 7036 |     } | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 7037 |  | 
 | 7038 |     AssertNoAllocation no_gc; | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 7039 |     FixedArray* array = reinterpret_cast<FixedArray*>(obj); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7040 |     array->set_map(isolate->heap()->fixed_array_map()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7041 |     array->set_length(length); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 7042 |  | 
 | 7043 |     WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7044 |     for (int i = 0; i < length; i++) { | 
 | 7045 |       array->set(i, *--parameters, mode); | 
 | 7046 |     } | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 7047 |     JSObject::cast(result)->set_elements(FixedArray::cast(obj)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7048 |   } | 
 | 7049 |   return result; | 
 | 7050 | } | 
 | 7051 |  | 
 | 7052 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7053 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7054 |   HandleScope scope(isolate); | 
| Shimeng (Simon) Wang | 8a31eba | 2010-12-06 19:01:33 -0800 | [diff] [blame] | 7055 |   ASSERT(args.length() == 3); | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 7056 |   CONVERT_ARG_CHECKED(Context, context, 0); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 7057 |   CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1); | 
| Shimeng (Simon) Wang | 8a31eba | 2010-12-06 19:01:33 -0800 | [diff] [blame] | 7058 |   CONVERT_BOOLEAN_CHECKED(pretenure, args[2]); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7059 |  | 
| Shimeng (Simon) Wang | 8a31eba | 2010-12-06 19:01:33 -0800 | [diff] [blame] | 7060 |   // Allocate global closures in old space and allocate local closures | 
 | 7061 |   // in new space. Additionally pretenure closures that are assigned | 
 | 7062 |   // directly to properties. | 
 | 7063 |   pretenure = pretenure || (context->global_context() == *context); | 
 | 7064 |   PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7065 |   Handle<JSFunction> result = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7066 |       isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, | 
 | 7067 |                                                             context, | 
 | 7068 |                                                             pretenure_flag); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7069 |   return *result; | 
 | 7070 | } | 
 | 7071 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7072 |  | 
 | 7073 | static SmartPointer<Object**> GetNonBoundArguments(int bound_argc, | 
 | 7074 |                                                    int* total_argc) { | 
 | 7075 |   // Find frame containing arguments passed to the caller. | 
 | 7076 |   JavaScriptFrameIterator it; | 
 | 7077 |   JavaScriptFrame* frame = it.frame(); | 
 | 7078 |   List<JSFunction*> functions(2); | 
 | 7079 |   frame->GetFunctions(&functions); | 
 | 7080 |   if (functions.length() > 1) { | 
 | 7081 |     int inlined_frame_index = functions.length() - 1; | 
 | 7082 |     JSFunction* inlined_function = functions[inlined_frame_index]; | 
 | 7083 |     int args_count = inlined_function->shared()->formal_parameter_count(); | 
 | 7084 |     ScopedVector<SlotRef> args_slots(args_count); | 
 | 7085 |     SlotRef::ComputeSlotMappingForArguments(frame, | 
 | 7086 |                                             inlined_frame_index, | 
 | 7087 |                                             &args_slots); | 
 | 7088 |  | 
 | 7089 |     *total_argc = bound_argc + args_count; | 
 | 7090 |     SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc)); | 
 | 7091 |     for (int i = 0; i < args_count; i++) { | 
 | 7092 |       Handle<Object> val = args_slots[i].GetValue(); | 
 | 7093 |       param_data[bound_argc + i] = val.location(); | 
 | 7094 |     } | 
 | 7095 |     return param_data; | 
 | 7096 |   } else { | 
 | 7097 |     it.AdvanceToArgumentsFrame(); | 
 | 7098 |     frame = it.frame(); | 
 | 7099 |     int args_count = frame->ComputeParametersCount(); | 
 | 7100 |  | 
 | 7101 |     *total_argc = bound_argc + args_count; | 
 | 7102 |     SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc)); | 
 | 7103 |     for (int i = 0; i < args_count; i++) { | 
 | 7104 |       Handle<Object> val = Handle<Object>(frame->GetParameter(i)); | 
 | 7105 |       param_data[bound_argc + i] = val.location(); | 
 | 7106 |     } | 
 | 7107 |     return param_data; | 
 | 7108 |   } | 
 | 7109 | } | 
 | 7110 |  | 
 | 7111 |  | 
 | 7112 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7113 |   HandleScope scope(isolate); | 
| Kristian Monsen | 50ef84f | 2010-07-29 15:18:00 +0100 | [diff] [blame] | 7114 |   ASSERT(args.length() == 2); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7115 |   // First argument is a function to use as a constructor. | 
| Kristian Monsen | 50ef84f | 2010-07-29 15:18:00 +0100 | [diff] [blame] | 7116 |   CONVERT_ARG_CHECKED(JSFunction, function, 0); | 
| Kristian Monsen | 50ef84f | 2010-07-29 15:18:00 +0100 | [diff] [blame] | 7117 |  | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7118 |   // Second argument is either null or an array of bound arguments. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7119 |   Handle<FixedArray> bound_args; | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7120 |   int bound_argc = 0; | 
 | 7121 |   if (!args[1]->IsNull()) { | 
 | 7122 |     CONVERT_ARG_CHECKED(JSArray, params, 1); | 
 | 7123 |     RUNTIME_ASSERT(params->HasFastElements()); | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7124 |     bound_args = Handle<FixedArray>(FixedArray::cast(params->elements())); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7125 |     bound_argc = Smi::cast(params->length())->value(); | 
 | 7126 |   } | 
| Kristian Monsen | 50ef84f | 2010-07-29 15:18:00 +0100 | [diff] [blame] | 7127 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7128 |   int total_argc = 0; | 
 | 7129 |   SmartPointer<Object**> param_data = | 
 | 7130 |       GetNonBoundArguments(bound_argc, &total_argc); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7131 |   for (int i = 0; i < bound_argc; i++) { | 
 | 7132 |     Handle<Object> val = Handle<Object>(bound_args->get(i)); | 
| Kristian Monsen | 50ef84f | 2010-07-29 15:18:00 +0100 | [diff] [blame] | 7133 |     param_data[i] = val.location(); | 
 | 7134 |   } | 
 | 7135 |  | 
| Ben Murdoch | bb769b2 | 2010-08-11 14:56:33 +0100 | [diff] [blame] | 7136 |   bool exception = false; | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7137 |   Handle<Object> result = | 
 | 7138 |       Execution::New(function, total_argc, *param_data, &exception); | 
| Ben Murdoch | bb769b2 | 2010-08-11 14:56:33 +0100 | [diff] [blame] | 7139 |   if (exception) { | 
 | 7140 |       return Failure::Exception(); | 
 | 7141 |   } | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7142 |  | 
| Ben Murdoch | bb769b2 | 2010-08-11 14:56:33 +0100 | [diff] [blame] | 7143 |   ASSERT(!result.is_null()); | 
| Kristian Monsen | 50ef84f | 2010-07-29 15:18:00 +0100 | [diff] [blame] | 7144 |   return *result; | 
 | 7145 | } | 
 | 7146 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7147 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7148 | static void TrySettingInlineConstructStub(Isolate* isolate, | 
 | 7149 |                                           Handle<JSFunction> function) { | 
 | 7150 |   Handle<Object> prototype = isolate->factory()->null_value(); | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 7151 |   if (function->has_instance_prototype()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7152 |     prototype = Handle<Object>(function->instance_prototype(), isolate); | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 7153 |   } | 
 | 7154 |   if (function->shared()->CanGenerateInlineConstructor(*prototype)) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7155 |     ConstructStubCompiler compiler; | 
| Shimeng (Simon) Wang | 8a31eba | 2010-12-06 19:01:33 -0800 | [diff] [blame] | 7156 |     MaybeObject* code = compiler.CompileConstructStub(*function); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 7157 |     if (!code->IsFailure()) { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7158 |       function->shared()->set_construct_stub( | 
 | 7159 |           Code::cast(code->ToObjectUnchecked())); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7160 |     } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7161 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7162 | } | 
 | 7163 |  | 
 | 7164 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7165 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7166 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7167 |   ASSERT(args.length() == 1); | 
 | 7168 |  | 
 | 7169 |   Handle<Object> constructor = args.at<Object>(0); | 
 | 7170 |  | 
 | 7171 |   // If the constructor isn't a proper function we throw a type error. | 
 | 7172 |   if (!constructor->IsJSFunction()) { | 
 | 7173 |     Vector< Handle<Object> > arguments = HandleVector(&constructor, 1); | 
 | 7174 |     Handle<Object> type_error = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7175 |         isolate->factory()->NewTypeError("not_constructor", arguments); | 
 | 7176 |     return isolate->Throw(*type_error); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7177 |   } | 
 | 7178 |  | 
 | 7179 |   Handle<JSFunction> function = Handle<JSFunction>::cast(constructor); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 7180 |  | 
 | 7181 |   // If function should not have prototype, construction is not allowed. In this | 
 | 7182 |   // case generated code bailouts here, since function has no initial_map. | 
 | 7183 |   if (!function->should_have_prototype()) { | 
 | 7184 |     Vector< Handle<Object> > arguments = HandleVector(&constructor, 1); | 
 | 7185 |     Handle<Object> type_error = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7186 |         isolate->factory()->NewTypeError("not_constructor", arguments); | 
 | 7187 |     return isolate->Throw(*type_error); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 7188 |   } | 
 | 7189 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7190 | #ifdef ENABLE_DEBUGGER_SUPPORT | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7191 |   Debug* debug = isolate->debug(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7192 |   // Handle stepping into constructors if step into is active. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7193 |   if (debug->StepInActive()) { | 
 | 7194 |     debug->HandleStepIn(function, Handle<Object>::null(), 0, true); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7195 |   } | 
 | 7196 | #endif | 
 | 7197 |  | 
 | 7198 |   if (function->has_initial_map()) { | 
 | 7199 |     if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) { | 
 | 7200 |       // The 'Function' function ignores the receiver object when | 
 | 7201 |       // called using 'new' and creates a new JSFunction object that | 
 | 7202 |       // is returned.  The receiver object is only used for error | 
 | 7203 |       // reporting if an error occurs when constructing the new | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7204 |       // JSFunction. FACTORY->NewJSObject() should not be used to | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7205 |       // allocate JSFunctions since it does not properly initialize | 
 | 7206 |       // the shared part of the function. Since the receiver is | 
 | 7207 |       // ignored anyway, we use the global object as the receiver | 
 | 7208 |       // instead of a new JSFunction object. This way, errors are | 
 | 7209 |       // reported the same way whether or not 'Function' is called | 
 | 7210 |       // using 'new'. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7211 |       return isolate->context()->global(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7212 |     } | 
 | 7213 |   } | 
 | 7214 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7215 |   // The function should be compiled for the optimization hints to be | 
 | 7216 |   // available. We cannot use EnsureCompiled because that forces a | 
 | 7217 |   // compilation through the shared function info which makes it | 
 | 7218 |   // impossible for us to optimize. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7219 |   Handle<SharedFunctionInfo> shared(function->shared(), isolate); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7220 |   if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7221 |  | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 7222 |   if (!function->has_initial_map() && | 
 | 7223 |       shared->IsInobjectSlackTrackingInProgress()) { | 
 | 7224 |     // The tracking is already in progress for another function. We can only | 
 | 7225 |     // track one initial_map at a time, so we force the completion before the | 
 | 7226 |     // function is called as a constructor for the first time. | 
 | 7227 |     shared->CompleteInobjectSlackTracking(); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 7228 |   } | 
 | 7229 |  | 
 | 7230 |   bool first_allocation = !shared->live_objects_may_exist(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7231 |   Handle<JSObject> result = isolate->factory()->NewJSObject(function); | 
 | 7232 |   RETURN_IF_EMPTY_HANDLE(isolate, result); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 7233 |   // Delay setting the stub if inobject slack tracking is in progress. | 
 | 7234 |   if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7235 |     TrySettingInlineConstructStub(isolate, function); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7236 |   } | 
 | 7237 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7238 |   isolate->counters()->constructed_objects()->Increment(); | 
 | 7239 |   isolate->counters()->constructed_objects_runtime()->Increment(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7240 |  | 
 | 7241 |   return *result; | 
 | 7242 | } | 
 | 7243 |  | 
 | 7244 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7245 | RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7246 |   HandleScope scope(isolate); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 7247 |   ASSERT(args.length() == 1); | 
 | 7248 |  | 
 | 7249 |   CONVERT_ARG_CHECKED(JSFunction, function, 0); | 
 | 7250 |   function->shared()->CompleteInobjectSlackTracking(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7251 |   TrySettingInlineConstructStub(isolate, function); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 7252 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7253 |   return isolate->heap()->undefined_value(); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 7254 | } | 
 | 7255 |  | 
 | 7256 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7257 | RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7258 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7259 |   ASSERT(args.length() == 1); | 
 | 7260 |  | 
 | 7261 |   Handle<JSFunction> function = args.at<JSFunction>(0); | 
 | 7262 | #ifdef DEBUG | 
| Iain Merrick | 7568138 | 2010-08-19 15:07:18 +0100 | [diff] [blame] | 7263 |   if (FLAG_trace_lazy && !function->shared()->is_compiled()) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7264 |     PrintF("[lazy: "); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7265 |     function->PrintName(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7266 |     PrintF("]\n"); | 
 | 7267 |   } | 
 | 7268 | #endif | 
 | 7269 |  | 
 | 7270 |   // Compile the target function.  Here we compile using CompileLazyInLoop in | 
 | 7271 |   // order to get the optimized version.  This helps code like delta-blue | 
 | 7272 |   // that calls performance-critical routines through constructors.  A | 
 | 7273 |   // constructor call doesn't use a CallIC, it uses a LoadIC followed by a | 
 | 7274 |   // direct call.  Since the in-loop tracking takes place through CallICs | 
 | 7275 |   // this means that things called through constructors are never known to | 
 | 7276 |   // be in loops.  We compile them as if they are in loops here just in case. | 
 | 7277 |   ASSERT(!function->is_compiled()); | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 7278 |   if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7279 |     return Failure::Exception(); | 
 | 7280 |   } | 
 | 7281 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7282 |   // All done. Return the compiled code. | 
 | 7283 |   ASSERT(function->is_compiled()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7284 |   return function->code(); | 
 | 7285 | } | 
 | 7286 |  | 
 | 7287 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7288 | RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7289 |   HandleScope scope(isolate); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7290 |   ASSERT(args.length() == 1); | 
 | 7291 |   Handle<JSFunction> function = args.at<JSFunction>(0); | 
 | 7292 |   // If the function is not optimizable or debugger is active continue using the | 
 | 7293 |   // code from the full compiler. | 
 | 7294 |   if (!function->shared()->code()->optimizable() || | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7295 |       isolate->debug()->has_break_points()) { | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 7296 |     if (FLAG_trace_opt) { | 
 | 7297 |       PrintF("[failed to optimize "); | 
 | 7298 |       function->PrintName(); | 
 | 7299 |       PrintF(": is code optimizable: %s, is debugger enabled: %s]\n", | 
 | 7300 |           function->shared()->code()->optimizable() ? "T" : "F", | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7301 |           isolate->debug()->has_break_points() ? "T" : "F"); | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 7302 |     } | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7303 |     function->ReplaceCode(function->shared()->code()); | 
 | 7304 |     return function->code(); | 
 | 7305 |   } | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 7306 |   if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) { | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7307 |     return function->code(); | 
 | 7308 |   } | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 7309 |   if (FLAG_trace_opt) { | 
 | 7310 |     PrintF("[failed to optimize "); | 
 | 7311 |     function->PrintName(); | 
 | 7312 |     PrintF(": optimized compilation failed]\n"); | 
 | 7313 |   } | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7314 |   function->ReplaceCode(function->shared()->code()); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 7315 |   return function->code(); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7316 | } | 
 | 7317 |  | 
 | 7318 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7319 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7320 |   HandleScope scope(isolate); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7321 |   ASSERT(args.length() == 1); | 
 | 7322 |   RUNTIME_ASSERT(args[0]->IsSmi()); | 
 | 7323 |   Deoptimizer::BailoutType type = | 
 | 7324 |       static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7325 |   Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate); | 
 | 7326 |   ASSERT(isolate->heap()->IsAllocationAllowed()); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7327 |   int frames = deoptimizer->output_count(); | 
 | 7328 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7329 |   deoptimizer->MaterializeHeapNumbers(); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7330 |   delete deoptimizer; | 
 | 7331 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7332 |   JavaScriptFrameIterator it(isolate); | 
 | 7333 |   JavaScriptFrame* frame = NULL; | 
 | 7334 |   for (int i = 0; i < frames - 1; i++) it.Advance(); | 
 | 7335 |   frame = it.frame(); | 
 | 7336 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7337 |   RUNTIME_ASSERT(frame->function()->IsJSFunction()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7338 |   Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7339 |   Handle<Object> arguments; | 
 | 7340 |   for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7341 |     if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) { | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7342 |       if (arguments.is_null()) { | 
 | 7343 |         // FunctionGetArguments can't throw an exception, so cast away the | 
 | 7344 |         // doubt with an assert. | 
 | 7345 |         arguments = Handle<Object>( | 
 | 7346 |             Accessors::FunctionGetArguments(*function, | 
 | 7347 |                                             NULL)->ToObjectUnchecked()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7348 |         ASSERT(*arguments != isolate->heap()->null_value()); | 
 | 7349 |         ASSERT(*arguments != isolate->heap()->undefined_value()); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7350 |       } | 
 | 7351 |       frame->SetExpression(i, *arguments); | 
 | 7352 |     } | 
 | 7353 |   } | 
 | 7354 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7355 |   isolate->compilation_cache()->MarkForLazyOptimizing(function); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7356 |   if (type == Deoptimizer::EAGER) { | 
 | 7357 |     RUNTIME_ASSERT(function->IsOptimized()); | 
 | 7358 |   } else { | 
 | 7359 |     RUNTIME_ASSERT(!function->IsOptimized()); | 
 | 7360 |   } | 
 | 7361 |  | 
 | 7362 |   // Avoid doing too much work when running with --always-opt and keep | 
 | 7363 |   // the optimized code around. | 
 | 7364 |   if (FLAG_always_opt || type == Deoptimizer::LAZY) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7365 |     return isolate->heap()->undefined_value(); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7366 |   } | 
 | 7367 |  | 
 | 7368 |   // Count the number of optimized activations of the function. | 
 | 7369 |   int activations = 0; | 
 | 7370 |   while (!it.done()) { | 
 | 7371 |     JavaScriptFrame* frame = it.frame(); | 
 | 7372 |     if (frame->is_optimized() && frame->function() == *function) { | 
 | 7373 |       activations++; | 
 | 7374 |     } | 
 | 7375 |     it.Advance(); | 
 | 7376 |   } | 
 | 7377 |  | 
 | 7378 |   // TODO(kasperl): For now, we cannot support removing the optimized | 
 | 7379 |   // code when we have recursive invocations of the same function. | 
 | 7380 |   if (activations == 0) { | 
 | 7381 |     if (FLAG_trace_deopt) { | 
 | 7382 |       PrintF("[removing optimized code for: "); | 
 | 7383 |       function->PrintName(); | 
 | 7384 |       PrintF("]\n"); | 
 | 7385 |     } | 
 | 7386 |     function->ReplaceCode(function->shared()->code()); | 
 | 7387 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7388 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7389 | } | 
 | 7390 |  | 
 | 7391 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7392 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7393 |   Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7394 |   delete deoptimizer; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7395 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7396 | } | 
 | 7397 |  | 
 | 7398 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7399 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7400 |   HandleScope scope(isolate); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7401 |   ASSERT(args.length() == 1); | 
 | 7402 |   CONVERT_ARG_CHECKED(JSFunction, function, 0); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7403 |   if (!function->IsOptimized()) return isolate->heap()->undefined_value(); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7404 |  | 
 | 7405 |   Deoptimizer::DeoptimizeFunction(*function); | 
 | 7406 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7407 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7408 | } | 
 | 7409 |  | 
 | 7410 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7411 | RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) { | 
 | 7412 |   HandleScope scope(isolate); | 
 | 7413 |   ASSERT(args.length() == 1); | 
 | 7414 |   CONVERT_ARG_CHECKED(JSFunction, function, 0); | 
 | 7415 |   if (!function->IsOptimizable()) return isolate->heap()->undefined_value(); | 
 | 7416 |   function->MarkForLazyRecompilation(); | 
 | 7417 |   return isolate->heap()->undefined_value(); | 
 | 7418 | } | 
 | 7419 |  | 
 | 7420 |  | 
 | 7421 | RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7422 |   HandleScope scope(isolate); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7423 |   ASSERT(args.length() == 1); | 
 | 7424 |   CONVERT_ARG_CHECKED(JSFunction, function, 0); | 
 | 7425 |  | 
 | 7426 |   // We're not prepared to handle a function with arguments object. | 
 | 7427 |   ASSERT(!function->shared()->scope_info()->HasArgumentsShadow()); | 
 | 7428 |  | 
 | 7429 |   // We have hit a back edge in an unoptimized frame for a function that was | 
 | 7430 |   // selected for on-stack replacement.  Find the unoptimized code object. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7431 |   Handle<Code> unoptimized(function->shared()->code(), isolate); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7432 |   // Keep track of whether we've succeeded in optimizing. | 
 | 7433 |   bool succeeded = unoptimized->optimizable(); | 
 | 7434 |   if (succeeded) { | 
 | 7435 |     // If we are trying to do OSR when there are already optimized | 
 | 7436 |     // activations of the function, it means (a) the function is directly or | 
 | 7437 |     // indirectly recursive and (b) an optimized invocation has been | 
 | 7438 |     // deoptimized so that we are currently in an unoptimized activation. | 
 | 7439 |     // Check for optimized activations of this function. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7440 |     JavaScriptFrameIterator it(isolate); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7441 |     while (succeeded && !it.done()) { | 
 | 7442 |       JavaScriptFrame* frame = it.frame(); | 
 | 7443 |       succeeded = !frame->is_optimized() || frame->function() != *function; | 
 | 7444 |       it.Advance(); | 
 | 7445 |     } | 
 | 7446 |   } | 
 | 7447 |  | 
 | 7448 |   int ast_id = AstNode::kNoNumber; | 
 | 7449 |   if (succeeded) { | 
 | 7450 |     // The top JS function is this one, the PC is somewhere in the | 
 | 7451 |     // unoptimized code. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7452 |     JavaScriptFrameIterator it(isolate); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7453 |     JavaScriptFrame* frame = it.frame(); | 
 | 7454 |     ASSERT(frame->function() == *function); | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7455 |     ASSERT(frame->LookupCode() == *unoptimized); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7456 |     ASSERT(unoptimized->contains(frame->pc())); | 
 | 7457 |  | 
 | 7458 |     // Use linear search of the unoptimized code's stack check table to find | 
 | 7459 |     // the AST id matching the PC. | 
 | 7460 |     Address start = unoptimized->instruction_start(); | 
 | 7461 |     unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7462 |     Address table_cursor = start + unoptimized->stack_check_table_offset(); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7463 |     uint32_t table_length = Memory::uint32_at(table_cursor); | 
 | 7464 |     table_cursor += kIntSize; | 
 | 7465 |     for (unsigned i = 0; i < table_length; ++i) { | 
 | 7466 |       // Table entries are (AST id, pc offset) pairs. | 
 | 7467 |       uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize); | 
 | 7468 |       if (pc_offset == target_pc_offset) { | 
 | 7469 |         ast_id = static_cast<int>(Memory::uint32_at(table_cursor)); | 
 | 7470 |         break; | 
 | 7471 |       } | 
 | 7472 |       table_cursor += 2 * kIntSize; | 
 | 7473 |     } | 
 | 7474 |     ASSERT(ast_id != AstNode::kNoNumber); | 
 | 7475 |     if (FLAG_trace_osr) { | 
 | 7476 |       PrintF("[replacing on-stack at AST id %d in ", ast_id); | 
 | 7477 |       function->PrintName(); | 
 | 7478 |       PrintF("]\n"); | 
 | 7479 |     } | 
 | 7480 |  | 
 | 7481 |     // Try to compile the optimized code.  A true return value from | 
 | 7482 |     // CompileOptimized means that compilation succeeded, not necessarily | 
 | 7483 |     // that optimization succeeded. | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 7484 |     if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) && | 
 | 7485 |         function->IsOptimized()) { | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7486 |       DeoptimizationInputData* data = DeoptimizationInputData::cast( | 
 | 7487 |           function->code()->deoptimization_data()); | 
 | 7488 |       if (data->OsrPcOffset()->value() >= 0) { | 
 | 7489 |         if (FLAG_trace_osr) { | 
 | 7490 |           PrintF("[on-stack replacement offset %d in optimized code]\n", | 
 | 7491 |                data->OsrPcOffset()->value()); | 
 | 7492 |         } | 
 | 7493 |         ASSERT(data->OsrAstId()->value() == ast_id); | 
 | 7494 |       } else { | 
 | 7495 |         // We may never generate the desired OSR entry if we emit an | 
 | 7496 |         // early deoptimize. | 
 | 7497 |         succeeded = false; | 
 | 7498 |       } | 
 | 7499 |     } else { | 
 | 7500 |       succeeded = false; | 
 | 7501 |     } | 
 | 7502 |   } | 
 | 7503 |  | 
 | 7504 |   // Revert to the original stack checks in the original unoptimized code. | 
 | 7505 |   if (FLAG_trace_osr) { | 
 | 7506 |     PrintF("[restoring original stack checks in "); | 
 | 7507 |     function->PrintName(); | 
 | 7508 |     PrintF("]\n"); | 
 | 7509 |   } | 
 | 7510 |   StackCheckStub check_stub; | 
 | 7511 |   Handle<Code> check_code = check_stub.GetCode(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7512 |   Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement(); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7513 |   Deoptimizer::RevertStackCheckCode(*unoptimized, | 
 | 7514 |                                     *check_code, | 
 | 7515 |                                     *replacement_code); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7516 |  | 
 | 7517 |   // Allow OSR only at nesting level zero again. | 
 | 7518 |   unoptimized->set_allow_osr_at_loop_nesting_level(0); | 
 | 7519 |  | 
 | 7520 |   // If the optimization attempt succeeded, return the AST id tagged as a | 
 | 7521 |   // smi. This tells the builtin that we need to translate the unoptimized | 
 | 7522 |   // frame to an optimized one. | 
 | 7523 |   if (succeeded) { | 
 | 7524 |     ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION); | 
 | 7525 |     return Smi::FromInt(ast_id); | 
 | 7526 |   } else { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 7527 |     if (function->IsMarkedForLazyRecompilation()) { | 
 | 7528 |       function->ReplaceCode(function->shared()->code()); | 
 | 7529 |     } | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 7530 |     return Smi::FromInt(-1); | 
 | 7531 |   } | 
 | 7532 | } | 
 | 7533 |  | 
 | 7534 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7535 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7536 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7537 |   ASSERT(args.length() == 1); | 
 | 7538 |   RUNTIME_ASSERT(!args[0]->IsJSFunction()); | 
 | 7539 |   return *Execution::GetFunctionDelegate(args.at<Object>(0)); | 
 | 7540 | } | 
 | 7541 |  | 
 | 7542 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7543 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7544 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7545 |   ASSERT(args.length() == 1); | 
 | 7546 |   RUNTIME_ASSERT(!args[0]->IsJSFunction()); | 
 | 7547 |   return *Execution::GetConstructorDelegate(args.at<Object>(0)); | 
 | 7548 | } | 
 | 7549 |  | 
 | 7550 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7551 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7552 |   NoHandleAllocation ha; | 
 | 7553 |   ASSERT(args.length() == 1); | 
 | 7554 |  | 
 | 7555 |   CONVERT_CHECKED(JSFunction, function, args[0]); | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 7556 |   int length = function->shared()->scope_info()->NumberOfContextSlots(); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7557 |   Object* result; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7558 |   { MaybeObject* maybe_result = | 
 | 7559 |         isolate->heap()->AllocateFunctionContext(length, function); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7560 |     if (!maybe_result->ToObject(&result)) return maybe_result; | 
 | 7561 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7562 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7563 |   isolate->set_context(Context::cast(result)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7564 |  | 
 | 7565 |   return result;  // non-failure | 
 | 7566 | } | 
 | 7567 |  | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7568 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7569 | MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate, | 
 | 7570 |                                                       Object* object, | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7571 |                                                       bool is_catch_context) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7572 |   // Convert the object to a proper JavaScript object. | 
 | 7573 |   Object* js_object = object; | 
 | 7574 |   if (!js_object->IsJSObject()) { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7575 |     MaybeObject* maybe_js_object = js_object->ToObject(); | 
 | 7576 |     if (!maybe_js_object->ToObject(&js_object)) { | 
 | 7577 |       if (!Failure::cast(maybe_js_object)->IsInternalError()) { | 
 | 7578 |         return maybe_js_object; | 
 | 7579 |       } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7580 |       HandleScope scope(isolate); | 
 | 7581 |       Handle<Object> handle(object, isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7582 |       Handle<Object> result = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7583 |           isolate->factory()->NewTypeError("with_expression", | 
 | 7584 |                                            HandleVector(&handle, 1)); | 
 | 7585 |       return isolate->Throw(*result); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7586 |     } | 
 | 7587 |   } | 
 | 7588 |  | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7589 |   Object* result; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7590 |   { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext( | 
 | 7591 |       isolate->context(), JSObject::cast(js_object), is_catch_context); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7592 |     if (!maybe_result->ToObject(&result)) return maybe_result; | 
 | 7593 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7594 |  | 
 | 7595 |   Context* context = Context::cast(result); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7596 |   isolate->set_context(context); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7597 |  | 
 | 7598 |   return result; | 
 | 7599 | } | 
 | 7600 |  | 
 | 7601 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7602 | RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7603 |   NoHandleAllocation ha; | 
 | 7604 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7605 |   return PushContextHelper(isolate, args[0], false); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7606 | } | 
 | 7607 |  | 
 | 7608 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7609 | RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7610 |   NoHandleAllocation ha; | 
 | 7611 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7612 |   return PushContextHelper(isolate, args[0], true); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7613 | } | 
 | 7614 |  | 
 | 7615 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7616 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7617 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7618 |   ASSERT(args.length() == 2); | 
 | 7619 |  | 
 | 7620 |   CONVERT_ARG_CHECKED(Context, context, 0); | 
 | 7621 |   CONVERT_ARG_CHECKED(String, name, 1); | 
 | 7622 |  | 
 | 7623 |   int index; | 
 | 7624 |   PropertyAttributes attributes; | 
 | 7625 |   ContextLookupFlags flags = FOLLOW_CHAINS; | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7626 |   Handle<Object> holder = context->Lookup(name, flags, &index, &attributes); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7627 |  | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7628 |   // If the slot was not found the result is true. | 
 | 7629 |   if (holder.is_null()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7630 |     return isolate->heap()->true_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7631 |   } | 
 | 7632 |  | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7633 |   // If the slot was found in a context, it should be DONT_DELETE. | 
 | 7634 |   if (holder->IsContext()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7635 |     return isolate->heap()->false_value(); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7636 |   } | 
 | 7637 |  | 
 | 7638 |   // The slot was found in a JSObject, either a context extension object, | 
 | 7639 |   // the global object, or an arguments object.  Try to delete it | 
 | 7640 |   // (respecting DONT_DELETE).  For consistency with V8's usual behavior, | 
 | 7641 |   // which allows deleting all parameters in functions that mention | 
 | 7642 |   // 'arguments', we do this even for the case of slots found on an | 
 | 7643 |   // arguments object.  The slot was found on an arguments object if the | 
 | 7644 |   // index is non-negative. | 
 | 7645 |   Handle<JSObject> object = Handle<JSObject>::cast(holder); | 
 | 7646 |   if (index >= 0) { | 
 | 7647 |     return object->DeleteElement(index, JSObject::NORMAL_DELETION); | 
 | 7648 |   } else { | 
 | 7649 |     return object->DeleteProperty(*name, JSObject::NORMAL_DELETION); | 
 | 7650 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7651 | } | 
 | 7652 |  | 
 | 7653 |  | 
 | 7654 | // A mechanism to return a pair of Object pointers in registers (if possible). | 
 | 7655 | // How this is achieved is calling convention-dependent. | 
 | 7656 | // All currently supported x86 compiles uses calling conventions that are cdecl | 
 | 7657 | // variants where a 64-bit value is returned in two 32-bit registers | 
 | 7658 | // (edx:eax on ia32, r1:r0 on ARM). | 
 | 7659 | // In AMD-64 calling convention a struct of two pointers is returned in rdx:rax. | 
 | 7660 | // In Win64 calling convention, a struct of two pointers is returned in memory, | 
 | 7661 | // allocated by the caller, and passed as a pointer in a hidden first parameter. | 
 | 7662 | #ifdef V8_HOST_ARCH_64_BIT | 
 | 7663 | struct ObjectPair { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7664 |   MaybeObject* x; | 
 | 7665 |   MaybeObject* y; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7666 | }; | 
 | 7667 |  | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7668 | static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7669 |   ObjectPair result = {x, y}; | 
 | 7670 |   // Pointers x and y returned in rax and rdx, in AMD-x64-abi. | 
 | 7671 |   // In Win64 they are assigned to a hidden first argument. | 
 | 7672 |   return result; | 
 | 7673 | } | 
 | 7674 | #else | 
 | 7675 | typedef uint64_t ObjectPair; | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7676 | static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7677 |   return reinterpret_cast<uint32_t>(x) | | 
 | 7678 |       (reinterpret_cast<ObjectPair>(y) << 32); | 
 | 7679 | } | 
 | 7680 | #endif | 
 | 7681 |  | 
 | 7682 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7683 | static inline MaybeObject* Unhole(Heap* heap, | 
 | 7684 |                                   MaybeObject* x, | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7685 |                                   PropertyAttributes attributes) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7686 |   ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0); | 
 | 7687 |   USE(attributes); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7688 |   return x->IsTheHole() ? heap->undefined_value() : x; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7689 | } | 
 | 7690 |  | 
 | 7691 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7692 | static JSObject* ComputeReceiverForNonGlobal(Isolate* isolate, | 
 | 7693 |                                              JSObject* holder) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7694 |   ASSERT(!holder->IsGlobalObject()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7695 |   Context* top = isolate->context(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7696 |   // Get the context extension function. | 
 | 7697 |   JSFunction* context_extension_function = | 
 | 7698 |       top->global_context()->context_extension_function(); | 
 | 7699 |   // If the holder isn't a context extension object, we just return it | 
 | 7700 |   // as the receiver. This allows arguments objects to be used as | 
 | 7701 |   // receivers, but only if they are put in the context scope chain | 
 | 7702 |   // explicitly via a with-statement. | 
 | 7703 |   Object* constructor = holder->map()->constructor(); | 
 | 7704 |   if (constructor != context_extension_function) return holder; | 
 | 7705 |   // Fall back to using the global object as the receiver if the | 
 | 7706 |   // property turns out to be a local variable allocated in a context | 
 | 7707 |   // extension object - introduced via eval. | 
 | 7708 |   return top->global()->global_receiver(); | 
 | 7709 | } | 
 | 7710 |  | 
 | 7711 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7712 | static ObjectPair LoadContextSlotHelper(Arguments args, | 
 | 7713 |                                         Isolate* isolate, | 
 | 7714 |                                         bool throw_error) { | 
 | 7715 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7716 |   ASSERT_EQ(2, args.length()); | 
 | 7717 |  | 
 | 7718 |   if (!args[0]->IsContext() || !args[1]->IsString()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7719 |     return MakePair(isolate->ThrowIllegalOperation(), NULL); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7720 |   } | 
 | 7721 |   Handle<Context> context = args.at<Context>(0); | 
 | 7722 |   Handle<String> name = args.at<String>(1); | 
 | 7723 |  | 
 | 7724 |   int index; | 
 | 7725 |   PropertyAttributes attributes; | 
 | 7726 |   ContextLookupFlags flags = FOLLOW_CHAINS; | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7727 |   Handle<Object> holder = context->Lookup(name, flags, &index, &attributes); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7728 |  | 
 | 7729 |   // If the index is non-negative, the slot has been found in a local | 
 | 7730 |   // variable or a parameter. Read it from the context object or the | 
 | 7731 |   // arguments object. | 
 | 7732 |   if (index >= 0) { | 
 | 7733 |     // If the "property" we were looking for is a local variable or an | 
 | 7734 |     // argument in a context, the receiver is the global object; see | 
 | 7735 |     // ECMA-262, 3rd., 10.1.6 and 10.2.3. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7736 |     JSObject* receiver = | 
 | 7737 |         isolate->context()->global()->global_receiver(); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7738 |     MaybeObject* value = (holder->IsContext()) | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7739 |         ? Context::cast(*holder)->get(index) | 
 | 7740 |         : JSObject::cast(*holder)->GetElement(index); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7741 |     return MakePair(Unhole(isolate->heap(), value, attributes), receiver); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7742 |   } | 
 | 7743 |  | 
 | 7744 |   // If the holder is found, we read the property from it. | 
 | 7745 |   if (!holder.is_null() && holder->IsJSObject()) { | 
 | 7746 |     ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name)); | 
 | 7747 |     JSObject* object = JSObject::cast(*holder); | 
 | 7748 |     JSObject* receiver; | 
 | 7749 |     if (object->IsGlobalObject()) { | 
 | 7750 |       receiver = GlobalObject::cast(object)->global_receiver(); | 
 | 7751 |     } else if (context->is_exception_holder(*holder)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7752 |       receiver = isolate->context()->global()->global_receiver(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7753 |     } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7754 |       receiver = ComputeReceiverForNonGlobal(isolate, object); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7755 |     } | 
 | 7756 |     // No need to unhole the value here. This is taken care of by the | 
 | 7757 |     // GetProperty function. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 7758 |     MaybeObject* value = object->GetProperty(*name); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7759 |     return MakePair(value, receiver); | 
 | 7760 |   } | 
 | 7761 |  | 
 | 7762 |   if (throw_error) { | 
 | 7763 |     // The property doesn't exist - throw exception. | 
 | 7764 |     Handle<Object> reference_error = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7765 |         isolate->factory()->NewReferenceError("not_defined", | 
 | 7766 |                                               HandleVector(&name, 1)); | 
 | 7767 |     return MakePair(isolate->Throw(*reference_error), NULL); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7768 |   } else { | 
 | 7769 |     // The property doesn't exist - return undefined | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7770 |     return MakePair(isolate->heap()->undefined_value(), | 
 | 7771 |                     isolate->heap()->undefined_value()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7772 |   } | 
 | 7773 | } | 
 | 7774 |  | 
 | 7775 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7776 | RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7777 |   return LoadContextSlotHelper(args, isolate, true); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7778 | } | 
 | 7779 |  | 
 | 7780 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7781 | RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7782 |   return LoadContextSlotHelper(args, isolate, false); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7783 | } | 
 | 7784 |  | 
 | 7785 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7786 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7787 |   HandleScope scope(isolate); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 7788 |   ASSERT(args.length() == 4); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7789 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7790 |   Handle<Object> value(args[0], isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7791 |   CONVERT_ARG_CHECKED(Context, context, 1); | 
 | 7792 |   CONVERT_ARG_CHECKED(String, name, 2); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 7793 |   CONVERT_SMI_CHECKED(strict_unchecked, args[3]); | 
 | 7794 |   RUNTIME_ASSERT(strict_unchecked == kStrictMode || | 
 | 7795 |                  strict_unchecked == kNonStrictMode); | 
 | 7796 |   StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7797 |  | 
 | 7798 |   int index; | 
 | 7799 |   PropertyAttributes attributes; | 
 | 7800 |   ContextLookupFlags flags = FOLLOW_CHAINS; | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7801 |   Handle<Object> holder = context->Lookup(name, flags, &index, &attributes); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7802 |  | 
 | 7803 |   if (index >= 0) { | 
 | 7804 |     if (holder->IsContext()) { | 
 | 7805 |       // Ignore if read_only variable. | 
 | 7806 |       if ((attributes & READ_ONLY) == 0) { | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7807 |         // Context is a fixed array and set cannot fail. | 
 | 7808 |         Context::cast(*holder)->set(index, *value); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 7809 |       } else if (strict_mode == kStrictMode) { | 
 | 7810 |         // Setting read only property in strict mode. | 
 | 7811 |         Handle<Object> error = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7812 |             isolate->factory()->NewTypeError("strict_cannot_assign", | 
 | 7813 |                                              HandleVector(&name, 1)); | 
 | 7814 |         return isolate->Throw(*error); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7815 |       } | 
 | 7816 |     } else { | 
 | 7817 |       ASSERT((attributes & READ_ONLY) == 0); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7818 |       Handle<Object> result = | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 7819 |           SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7820 |       if (result.is_null()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7821 |         ASSERT(isolate->has_pending_exception()); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 7822 |         return Failure::Exception(); | 
 | 7823 |       } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7824 |     } | 
 | 7825 |     return *value; | 
 | 7826 |   } | 
 | 7827 |  | 
 | 7828 |   // Slow case: The property is not in a FixedArray context. | 
 | 7829 |   // It is either in an JSObject extension context or it was not found. | 
 | 7830 |   Handle<JSObject> context_ext; | 
 | 7831 |  | 
 | 7832 |   if (!holder.is_null()) { | 
 | 7833 |     // The property exists in the extension context. | 
 | 7834 |     context_ext = Handle<JSObject>::cast(holder); | 
 | 7835 |   } else { | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7836 |     // The property was not found. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7837 |     ASSERT(attributes == ABSENT); | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7838 |  | 
 | 7839 |     if (strict_mode == kStrictMode) { | 
 | 7840 |       // Throw in strict mode (assignment to undefined variable). | 
 | 7841 |       Handle<Object> error = | 
 | 7842 |         isolate->factory()->NewReferenceError( | 
 | 7843 |             "not_defined", HandleVector(&name, 1)); | 
 | 7844 |       return isolate->Throw(*error); | 
 | 7845 |     } | 
 | 7846 |     // In non-strict mode, the property is stored in the global context. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7847 |     attributes = NONE; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7848 |     context_ext = Handle<JSObject>(isolate->context()->global()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7849 |   } | 
 | 7850 |  | 
 | 7851 |   // Set the property, but ignore if read_only variable on the context | 
 | 7852 |   // extension object itself. | 
 | 7853 |   if ((attributes & READ_ONLY) == 0 || | 
 | 7854 |       (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 7855 |     RETURN_IF_EMPTY_HANDLE( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7856 |         isolate, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 7857 |         SetProperty(context_ext, name, value, NONE, strict_mode)); | 
 | 7858 |   } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) { | 
 | 7859 |     // Setting read only property in strict mode. | 
 | 7860 |     Handle<Object> error = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7861 |       isolate->factory()->NewTypeError( | 
 | 7862 |           "strict_cannot_assign", HandleVector(&name, 1)); | 
 | 7863 |     return isolate->Throw(*error); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7864 |   } | 
 | 7865 |   return *value; | 
 | 7866 | } | 
 | 7867 |  | 
 | 7868 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7869 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7870 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7871 |   ASSERT(args.length() == 1); | 
 | 7872 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7873 |   return isolate->Throw(args[0]); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7874 | } | 
 | 7875 |  | 
 | 7876 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7877 | RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7878 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7879 |   ASSERT(args.length() == 1); | 
 | 7880 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7881 |   return isolate->ReThrow(args[0]); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7882 | } | 
 | 7883 |  | 
 | 7884 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7885 | RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) { | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 7886 |   ASSERT_EQ(0, args.length()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7887 |   return isolate->PromoteScheduledException(); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 7888 | } | 
 | 7889 |  | 
 | 7890 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7891 | RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7892 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7893 |   ASSERT(args.length() == 1); | 
 | 7894 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7895 |   Handle<Object> name(args[0], isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7896 |   Handle<Object> reference_error = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7897 |     isolate->factory()->NewReferenceError("not_defined", | 
 | 7898 |                                           HandleVector(&name, 1)); | 
 | 7899 |   return isolate->Throw(*reference_error); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7900 | } | 
 | 7901 |  | 
 | 7902 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 7903 | RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) { | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 7904 |   ASSERT(args.length() == 0); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7905 |  | 
 | 7906 |   // First check if this is a real stack overflow. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7907 |   if (isolate->stack_guard()->IsStackOverflow()) { | 
 | 7908 |     NoHandleAllocation na; | 
 | 7909 |     return isolate->StackOverflow(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7910 |   } | 
 | 7911 |  | 
 | 7912 |   return Execution::HandleStackGuardInterrupt(); | 
 | 7913 | } | 
 | 7914 |  | 
 | 7915 |  | 
 | 7916 | // NOTE: These PrintXXX functions are defined for all builds (not just | 
 | 7917 | // DEBUG builds) because we may want to be able to trace function | 
 | 7918 | // calls in all modes. | 
 | 7919 | static void PrintString(String* str) { | 
 | 7920 |   // not uncommon to have empty strings | 
 | 7921 |   if (str->length() > 0) { | 
 | 7922 |     SmartPointer<char> s = | 
 | 7923 |         str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); | 
 | 7924 |     PrintF("%s", *s); | 
 | 7925 |   } | 
 | 7926 | } | 
 | 7927 |  | 
 | 7928 |  | 
 | 7929 | static void PrintObject(Object* obj) { | 
 | 7930 |   if (obj->IsSmi()) { | 
 | 7931 |     PrintF("%d", Smi::cast(obj)->value()); | 
 | 7932 |   } else if (obj->IsString() || obj->IsSymbol()) { | 
 | 7933 |     PrintString(String::cast(obj)); | 
 | 7934 |   } else if (obj->IsNumber()) { | 
 | 7935 |     PrintF("%g", obj->Number()); | 
 | 7936 |   } else if (obj->IsFailure()) { | 
 | 7937 |     PrintF("<failure>"); | 
 | 7938 |   } else if (obj->IsUndefined()) { | 
 | 7939 |     PrintF("<undefined>"); | 
 | 7940 |   } else if (obj->IsNull()) { | 
 | 7941 |     PrintF("<null>"); | 
 | 7942 |   } else if (obj->IsTrue()) { | 
 | 7943 |     PrintF("<true>"); | 
 | 7944 |   } else if (obj->IsFalse()) { | 
 | 7945 |     PrintF("<false>"); | 
 | 7946 |   } else { | 
| Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 7947 |     PrintF("%p", reinterpret_cast<void*>(obj)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7948 |   } | 
 | 7949 | } | 
 | 7950 |  | 
 | 7951 |  | 
 | 7952 | static int StackSize() { | 
 | 7953 |   int n = 0; | 
 | 7954 |   for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++; | 
 | 7955 |   return n; | 
 | 7956 | } | 
 | 7957 |  | 
 | 7958 |  | 
 | 7959 | static void PrintTransition(Object* result) { | 
 | 7960 |   // indentation | 
 | 7961 |   { const int nmax = 80; | 
 | 7962 |     int n = StackSize(); | 
 | 7963 |     if (n <= nmax) | 
 | 7964 |       PrintF("%4d:%*s", n, n, ""); | 
 | 7965 |     else | 
 | 7966 |       PrintF("%4d:%*s", n, nmax, "..."); | 
 | 7967 |   } | 
 | 7968 |  | 
 | 7969 |   if (result == NULL) { | 
 | 7970 |     // constructor calls | 
 | 7971 |     JavaScriptFrameIterator it; | 
 | 7972 |     JavaScriptFrame* frame = it.frame(); | 
 | 7973 |     if (frame->IsConstructor()) PrintF("new "); | 
 | 7974 |     // function name | 
 | 7975 |     Object* fun = frame->function(); | 
 | 7976 |     if (fun->IsJSFunction()) { | 
 | 7977 |       PrintObject(JSFunction::cast(fun)->shared()->name()); | 
 | 7978 |     } else { | 
 | 7979 |       PrintObject(fun); | 
 | 7980 |     } | 
 | 7981 |     // function arguments | 
 | 7982 |     // (we are intentionally only printing the actually | 
 | 7983 |     // supplied parameters, not all parameters required) | 
 | 7984 |     PrintF("(this="); | 
 | 7985 |     PrintObject(frame->receiver()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 7986 |     const int length = frame->ComputeParametersCount(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 7987 |     for (int i = 0; i < length; i++) { | 
 | 7988 |       PrintF(", "); | 
 | 7989 |       PrintObject(frame->GetParameter(i)); | 
 | 7990 |     } | 
 | 7991 |     PrintF(") {\n"); | 
 | 7992 |  | 
 | 7993 |   } else { | 
 | 7994 |     // function result | 
 | 7995 |     PrintF("} -> "); | 
 | 7996 |     PrintObject(result); | 
 | 7997 |     PrintF("\n"); | 
 | 7998 |   } | 
 | 7999 | } | 
 | 8000 |  | 
 | 8001 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8002 | RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8003 |   ASSERT(args.length() == 0); | 
 | 8004 |   NoHandleAllocation ha; | 
 | 8005 |   PrintTransition(NULL); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8006 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8007 | } | 
 | 8008 |  | 
 | 8009 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8010 | RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8011 |   NoHandleAllocation ha; | 
 | 8012 |   PrintTransition(args[0]); | 
 | 8013 |   return args[0];  // return TOS | 
 | 8014 | } | 
 | 8015 |  | 
 | 8016 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8017 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8018 |   NoHandleAllocation ha; | 
 | 8019 |   ASSERT(args.length() == 1); | 
 | 8020 |  | 
 | 8021 | #ifdef DEBUG | 
 | 8022 |   if (args[0]->IsString()) { | 
 | 8023 |     // If we have a string, assume it's a code "marker" | 
 | 8024 |     // and print some interesting cpu debugging info. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8025 |     JavaScriptFrameIterator it(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8026 |     JavaScriptFrame* frame = it.frame(); | 
 | 8027 |     PrintF("fp = %p, sp = %p, caller_sp = %p: ", | 
 | 8028 |            frame->fp(), frame->sp(), frame->caller_sp()); | 
 | 8029 |   } else { | 
 | 8030 |     PrintF("DebugPrint: "); | 
 | 8031 |   } | 
 | 8032 |   args[0]->Print(); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 8033 |   if (args[0]->IsHeapObject()) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 8034 |     PrintF("\n"); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 8035 |     HeapObject::cast(args[0])->map()->Print(); | 
 | 8036 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8037 | #else | 
 | 8038 |   // ShortPrint is available in release mode. Print is not. | 
 | 8039 |   args[0]->ShortPrint(); | 
 | 8040 | #endif | 
 | 8041 |   PrintF("\n"); | 
 | 8042 |   Flush(); | 
 | 8043 |  | 
 | 8044 |   return args[0];  // return TOS | 
 | 8045 | } | 
 | 8046 |  | 
 | 8047 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8048 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8049 |   ASSERT(args.length() == 0); | 
 | 8050 |   NoHandleAllocation ha; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8051 |   isolate->PrintStack(); | 
 | 8052 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8053 | } | 
 | 8054 |  | 
 | 8055 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8056 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8057 |   NoHandleAllocation ha; | 
 | 8058 |   ASSERT(args.length() == 0); | 
 | 8059 |  | 
 | 8060 |   // According to ECMA-262, section 15.9.1, page 117, the precision of | 
 | 8061 |   // the number in a Date object representing a particular instant in | 
 | 8062 |   // time is milliseconds. Therefore, we floor the result of getting | 
 | 8063 |   // the OS time. | 
 | 8064 |   double millis = floor(OS::TimeCurrentMillis()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8065 |   return isolate->heap()->NumberFromDouble(millis); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8066 | } | 
 | 8067 |  | 
 | 8068 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8069 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8070 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8071 |   ASSERT(args.length() == 2); | 
 | 8072 |  | 
 | 8073 |   CONVERT_ARG_CHECKED(String, str, 0); | 
 | 8074 |   FlattenString(str); | 
 | 8075 |  | 
 | 8076 |   CONVERT_ARG_CHECKED(JSArray, output, 1); | 
 | 8077 |   RUNTIME_ASSERT(output->HasFastElements()); | 
 | 8078 |  | 
 | 8079 |   AssertNoAllocation no_allocation; | 
 | 8080 |  | 
 | 8081 |   FixedArray* output_array = FixedArray::cast(output->elements()); | 
 | 8082 |   RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE); | 
 | 8083 |   bool result; | 
 | 8084 |   if (str->IsAsciiRepresentation()) { | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8085 |     result = DateParser::Parse(str->ToAsciiVector(), | 
 | 8086 |                                output_array, | 
 | 8087 |                                isolate->unicode_cache()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8088 |   } else { | 
 | 8089 |     ASSERT(str->IsTwoByteRepresentation()); | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8090 |     result = DateParser::Parse(str->ToUC16Vector(), | 
 | 8091 |                                output_array, | 
 | 8092 |                                isolate->unicode_cache()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8093 |   } | 
 | 8094 |  | 
 | 8095 |   if (result) { | 
 | 8096 |     return *output; | 
 | 8097 |   } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8098 |     return isolate->heap()->null_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8099 |   } | 
 | 8100 | } | 
 | 8101 |  | 
 | 8102 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8103 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8104 |   NoHandleAllocation ha; | 
 | 8105 |   ASSERT(args.length() == 1); | 
 | 8106 |  | 
 | 8107 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
 | 8108 |   const char* zone = OS::LocalTimezone(x); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8109 |   return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8110 | } | 
 | 8111 |  | 
 | 8112 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8113 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8114 |   NoHandleAllocation ha; | 
 | 8115 |   ASSERT(args.length() == 0); | 
 | 8116 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8117 |   return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8118 | } | 
 | 8119 |  | 
 | 8120 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8121 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8122 |   NoHandleAllocation ha; | 
 | 8123 |   ASSERT(args.length() == 1); | 
 | 8124 |  | 
 | 8125 |   CONVERT_DOUBLE_CHECKED(x, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8126 |   return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8127 | } | 
 | 8128 |  | 
 | 8129 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8130 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8131 |   ASSERT(args.length() == 1); | 
 | 8132 |   Object* global = args[0]; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8133 |   if (!global->IsJSGlobalObject()) return isolate->heap()->null_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8134 |   return JSGlobalObject::cast(global)->global_receiver(); | 
 | 8135 | } | 
 | 8136 |  | 
 | 8137 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8138 | RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8139 |   HandleScope scope(isolate); | 
| Teng-Hui Zhu | 3e5fa29 | 2010-11-09 16:16:48 -0800 | [diff] [blame] | 8140 |   ASSERT_EQ(1, args.length()); | 
 | 8141 |   CONVERT_ARG_CHECKED(String, source, 0); | 
 | 8142 |  | 
 | 8143 |   Handle<Object> result = JsonParser::Parse(source); | 
 | 8144 |   if (result.is_null()) { | 
 | 8145 |     // Syntax error or stack overflow in scanner. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8146 |     ASSERT(isolate->has_pending_exception()); | 
| Teng-Hui Zhu | 3e5fa29 | 2010-11-09 16:16:48 -0800 | [diff] [blame] | 8147 |     return Failure::Exception(); | 
 | 8148 |   } | 
 | 8149 |   return *result; | 
 | 8150 | } | 
 | 8151 |  | 
 | 8152 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8153 | RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8154 |   HandleScope scope(isolate); | 
| Teng-Hui Zhu | 3e5fa29 | 2010-11-09 16:16:48 -0800 | [diff] [blame] | 8155 |   ASSERT_EQ(1, args.length()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8156 |   CONVERT_ARG_CHECKED(String, source, 0); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8157 |  | 
 | 8158 |   // Compile source string in the global context. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8159 |   Handle<Context> context(isolate->context()->global_context()); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 8160 |   Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source, | 
 | 8161 |                                                             context, | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 8162 |                                                             true, | 
 | 8163 |                                                             kNonStrictMode); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 8164 |   if (shared.is_null()) return Failure::Exception(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8165 |   Handle<JSFunction> fun = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8166 |       isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, | 
 | 8167 |                                                             context, | 
 | 8168 |                                                             NOT_TENURED); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8169 |   return *fun; | 
 | 8170 | } | 
 | 8171 |  | 
 | 8172 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8173 | static ObjectPair CompileGlobalEval(Isolate* isolate, | 
 | 8174 |                                     Handle<String> source, | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 8175 |                                     Handle<Object> receiver, | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8176 |                                     StrictModeFlag strict_mode) { | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 8177 |   // Deal with a normal eval call with a string argument. Compile it | 
 | 8178 |   // and return the compiled function bound in the local context. | 
 | 8179 |   Handle<SharedFunctionInfo> shared = Compiler::CompileEval( | 
 | 8180 |       source, | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8181 |       Handle<Context>(isolate->context()), | 
 | 8182 |       isolate->context()->IsGlobalContext(), | 
 | 8183 |       strict_mode); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 8184 |   if (shared.is_null()) return MakePair(Failure::Exception(), NULL); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8185 |   Handle<JSFunction> compiled = | 
 | 8186 |       isolate->factory()->NewFunctionFromSharedFunctionInfo( | 
 | 8187 |           shared, Handle<Context>(isolate->context()), NOT_TENURED); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 8188 |   return MakePair(*compiled, *receiver); | 
 | 8189 | } | 
 | 8190 |  | 
 | 8191 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8192 | RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) { | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 8193 |   ASSERT(args.length() == 4); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8194 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8195 |   HandleScope scope(isolate); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8196 |   Handle<Object> callee = args.at<Object>(0); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 8197 |   Handle<Object> receiver;  // Will be overwritten. | 
 | 8198 |  | 
 | 8199 |   // Compute the calling context. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8200 |   Handle<Context> context = Handle<Context>(isolate->context(), isolate); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 8201 | #ifdef DEBUG | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8202 |   // Make sure Isolate::context() agrees with the old code that traversed | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 8203 |   // the stack frames to compute the context. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8204 |   StackFrameLocator locator; | 
 | 8205 |   JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 8206 |   ASSERT(Context::cast(frame->context()) == *context); | 
 | 8207 | #endif | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8208 |  | 
 | 8209 |   // Find where the 'eval' symbol is bound. It is unaliased only if | 
 | 8210 |   // it is bound in the global context. | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 8211 |   int index = -1; | 
 | 8212 |   PropertyAttributes attributes = ABSENT; | 
 | 8213 |   while (true) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8214 |     receiver = context->Lookup(isolate->factory()->eval_symbol(), | 
 | 8215 |                                FOLLOW_PROTOTYPE_CHAIN, | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8216 |                                &index, &attributes); | 
 | 8217 |     // Stop search when eval is found or when the global context is | 
 | 8218 |     // reached. | 
 | 8219 |     if (attributes != ABSENT || context->IsGlobalContext()) break; | 
 | 8220 |     if (context->is_function_context()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8221 |       context = Handle<Context>(Context::cast(context->closure()->context()), | 
 | 8222 |                                 isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8223 |     } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8224 |       context = Handle<Context>(context->previous(), isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8225 |     } | 
 | 8226 |   } | 
 | 8227 |  | 
 | 8228 |   // If eval could not be resolved, it has been deleted and we need to | 
 | 8229 |   // throw a reference error. | 
 | 8230 |   if (attributes == ABSENT) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8231 |     Handle<Object> name = isolate->factory()->eval_symbol(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8232 |     Handle<Object> reference_error = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8233 |         isolate->factory()->NewReferenceError("not_defined", | 
 | 8234 |                                               HandleVector(&name, 1)); | 
 | 8235 |     return MakePair(isolate->Throw(*reference_error), NULL); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8236 |   } | 
 | 8237 |  | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 8238 |   if (!context->IsGlobalContext()) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8239 |     // 'eval' is not bound in the global context. Just call the function | 
 | 8240 |     // with the given arguments. This is not necessarily the global eval. | 
 | 8241 |     if (receiver->IsContext()) { | 
 | 8242 |       context = Handle<Context>::cast(receiver); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8243 |       receiver = Handle<Object>(context->get(index), isolate); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 8244 |     } else if (receiver->IsJSContextExtensionObject()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8245 |       receiver = Handle<JSObject>( | 
 | 8246 |           isolate->context()->global()->global_receiver(), isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8247 |     } | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 8248 |     return MakePair(*callee, *receiver); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8249 |   } | 
 | 8250 |  | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 8251 |   // 'eval' is bound in the global context, but it may have been overwritten. | 
 | 8252 |   // Compare it to the builtin 'GlobalEval' function to make sure. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8253 |   if (*callee != isolate->global_context()->global_eval_fun() || | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 8254 |       !args[1]->IsString()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8255 |     return MakePair(*callee, | 
 | 8256 |                     isolate->context()->global()->global_receiver()); | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 8257 |   } | 
 | 8258 |  | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 8259 |   ASSERT(args[3]->IsSmi()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8260 |   return CompileGlobalEval(isolate, | 
 | 8261 |                            args.at<String>(1), | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 8262 |                            args.at<Object>(2), | 
 | 8263 |                            static_cast<StrictModeFlag>( | 
 | 8264 |                                 Smi::cast(args[3])->value())); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 8265 | } | 
 | 8266 |  | 
 | 8267 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8268 | RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) { | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 8269 |   ASSERT(args.length() == 4); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 8270 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8271 |   HandleScope scope(isolate); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8272 |   Handle<Object> callee = args.at<Object>(0); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 8273 |  | 
 | 8274 |   // 'eval' is bound in the global context, but it may have been overwritten. | 
 | 8275 |   // Compare it to the builtin 'GlobalEval' function to make sure. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8276 |   if (*callee != isolate->global_context()->global_eval_fun() || | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 8277 |       !args[1]->IsString()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8278 |     return MakePair(*callee, | 
 | 8279 |                     isolate->context()->global()->global_receiver()); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 8280 |   } | 
 | 8281 |  | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 8282 |   ASSERT(args[3]->IsSmi()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8283 |   return CompileGlobalEval(isolate, | 
 | 8284 |                            args.at<String>(1), | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 8285 |                            args.at<Object>(2), | 
 | 8286 |                            static_cast<StrictModeFlag>( | 
 | 8287 |                                 Smi::cast(args[3])->value())); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8288 | } | 
 | 8289 |  | 
 | 8290 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8291 | RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8292 |   // This utility adjusts the property attributes for newly created Function | 
 | 8293 |   // object ("new Function(...)") by changing the map. | 
 | 8294 |   // All it does is changing the prototype property to enumerable | 
 | 8295 |   // as specified in ECMA262, 15.3.5.2. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8296 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8297 |   ASSERT(args.length() == 1); | 
 | 8298 |   CONVERT_ARG_CHECKED(JSFunction, func, 0); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8299 |  | 
 | 8300 |   Handle<Map> map = func->shared()->strict_mode() | 
 | 8301 |                         ? isolate->strict_mode_function_instance_map() | 
 | 8302 |                         : isolate->function_instance_map(); | 
 | 8303 |  | 
 | 8304 |   ASSERT(func->map()->instance_type() == map->instance_type()); | 
 | 8305 |   ASSERT(func->map()->instance_size() == map->instance_size()); | 
 | 8306 |   func->set_map(*map); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8307 |   return *func; | 
 | 8308 | } | 
 | 8309 |  | 
 | 8310 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8311 | RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) { | 
| Ben Murdoch | bb769b2 | 2010-08-11 14:56:33 +0100 | [diff] [blame] | 8312 |   // Allocate a block of memory in NewSpace (filled with a filler). | 
 | 8313 |   // Use as fallback for allocation in generated code when NewSpace | 
 | 8314 |   // is full. | 
 | 8315 |   ASSERT(args.length() == 1); | 
 | 8316 |   CONVERT_ARG_CHECKED(Smi, size_smi, 0); | 
 | 8317 |   int size = size_smi->value(); | 
 | 8318 |   RUNTIME_ASSERT(IsAligned(size, kPointerSize)); | 
 | 8319 |   RUNTIME_ASSERT(size > 0); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8320 |   Heap* heap = isolate->heap(); | 
 | 8321 |   const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4; | 
| Ben Murdoch | bb769b2 | 2010-08-11 14:56:33 +0100 | [diff] [blame] | 8322 |   RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 8323 |   Object* allocation; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8324 |   { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 8325 |     if (maybe_allocation->ToObject(&allocation)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8326 |       heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 8327 |     } | 
 | 8328 |     return maybe_allocation; | 
| Ben Murdoch | bb769b2 | 2010-08-11 14:56:33 +0100 | [diff] [blame] | 8329 |   } | 
| Ben Murdoch | bb769b2 | 2010-08-11 14:56:33 +0100 | [diff] [blame] | 8330 | } | 
 | 8331 |  | 
 | 8332 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 8333 | // Push an object unto an array of objects if it is not already in the | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8334 | // array.  Returns true if the element was pushed on the stack and | 
 | 8335 | // false otherwise. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8336 | RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8337 |   ASSERT(args.length() == 2); | 
 | 8338 |   CONVERT_CHECKED(JSArray, array, args[0]); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 8339 |   CONVERT_CHECKED(JSObject, element, args[1]); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8340 |   RUNTIME_ASSERT(array->HasFastElements()); | 
 | 8341 |   int length = Smi::cast(array->length())->value(); | 
 | 8342 |   FixedArray* elements = FixedArray::cast(array->elements()); | 
 | 8343 |   for (int i = 0; i < length; i++) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8344 |     if (elements->get(i) == element) return isolate->heap()->false_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8345 |   } | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 8346 |   Object* obj; | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8347 |   // Strict not needed. Used for cycle detection in Array join implementation. | 
 | 8348 |   { MaybeObject* maybe_obj = array->SetFastElement(length, element, | 
 | 8349 |                                                    kNonStrictMode); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 8350 |     if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 
 | 8351 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8352 |   return isolate->heap()->true_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8353 | } | 
 | 8354 |  | 
 | 8355 |  | 
 | 8356 | /** | 
 | 8357 |  * A simple visitor visits every element of Array's. | 
 | 8358 |  * The backend storage can be a fixed array for fast elements case, | 
 | 8359 |  * or a dictionary for sparse array. Since Dictionary is a subtype | 
 | 8360 |  * of FixedArray, the class can be used by both fast and slow cases. | 
 | 8361 |  * The second parameter of the constructor, fast_elements, specifies | 
 | 8362 |  * whether the storage is a FixedArray or Dictionary. | 
 | 8363 |  * | 
 | 8364 |  * An index limit is used to deal with the situation that a result array | 
 | 8365 |  * length overflows 32-bit non-negative integer. | 
 | 8366 |  */ | 
 | 8367 | class ArrayConcatVisitor { | 
 | 8368 |  public: | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8369 |   ArrayConcatVisitor(Isolate* isolate, | 
 | 8370 |                      Handle<FixedArray> storage, | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8371 |                      bool fast_elements) : | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8372 |       isolate_(isolate), | 
 | 8373 |       storage_(Handle<FixedArray>::cast( | 
 | 8374 |           isolate->global_handles()->Create(*storage))), | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8375 |       index_offset_(0u), | 
 | 8376 |       fast_elements_(fast_elements) { } | 
 | 8377 |  | 
 | 8378 |   ~ArrayConcatVisitor() { | 
 | 8379 |     clear_storage(); | 
 | 8380 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8381 |  | 
 | 8382 |   void visit(uint32_t i, Handle<Object> elm) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8383 |     if (i >= JSObject::kMaxElementCount - index_offset_) return; | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 8384 |     uint32_t index = index_offset_ + i; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8385 |  | 
 | 8386 |     if (fast_elements_) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8387 |       if (index < static_cast<uint32_t>(storage_->length())) { | 
 | 8388 |         storage_->set(index, *elm); | 
 | 8389 |         return; | 
 | 8390 |       } | 
 | 8391 |       // Our initial estimate of length was foiled, possibly by | 
 | 8392 |       // getters on the arrays increasing the length of later arrays | 
 | 8393 |       // during iteration. | 
 | 8394 |       // This shouldn't happen in anything but pathological cases. | 
 | 8395 |       SetDictionaryMode(index); | 
 | 8396 |       // Fall-through to dictionary mode. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8397 |     } | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8398 |     ASSERT(!fast_elements_); | 
 | 8399 |     Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_)); | 
 | 8400 |     Handle<NumberDictionary> result = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8401 |         isolate_->factory()->DictionaryAtNumberPut(dict, index, elm); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8402 |     if (!result.is_identical_to(dict)) { | 
 | 8403 |       // Dictionary needed to grow. | 
 | 8404 |       clear_storage(); | 
 | 8405 |       set_storage(*result); | 
 | 8406 |     } | 
 | 8407 | } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8408 |  | 
 | 8409 |   void increase_index_offset(uint32_t delta) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8410 |     if (JSObject::kMaxElementCount - index_offset_ < delta) { | 
 | 8411 |       index_offset_ = JSObject::kMaxElementCount; | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 8412 |     } else { | 
 | 8413 |       index_offset_ += delta; | 
 | 8414 |     } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8415 |   } | 
 | 8416 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8417 |   Handle<JSArray> ToArray() { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8418 |     Handle<JSArray> array = isolate_->factory()->NewJSArray(0); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8419 |     Handle<Object> length = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8420 |         isolate_->factory()->NewNumber(static_cast<double>(index_offset_)); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8421 |     Handle<Map> map; | 
 | 8422 |     if (fast_elements_) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8423 |       map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map())); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8424 |     } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8425 |       map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map())); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8426 |     } | 
 | 8427 |     array->set_map(*map); | 
 | 8428 |     array->set_length(*length); | 
 | 8429 |     array->set_elements(*storage_); | 
 | 8430 |     return array; | 
 | 8431 |   } | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 8432 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8433 |  private: | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8434 |   // Convert storage to dictionary mode. | 
 | 8435 |   void SetDictionaryMode(uint32_t index) { | 
 | 8436 |     ASSERT(fast_elements_); | 
 | 8437 |     Handle<FixedArray> current_storage(*storage_); | 
 | 8438 |     Handle<NumberDictionary> slow_storage( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8439 |         isolate_->factory()->NewNumberDictionary(current_storage->length())); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8440 |     uint32_t current_length = static_cast<uint32_t>(current_storage->length()); | 
 | 8441 |     for (uint32_t i = 0; i < current_length; i++) { | 
 | 8442 |       HandleScope loop_scope; | 
 | 8443 |       Handle<Object> element(current_storage->get(i)); | 
 | 8444 |       if (!element->IsTheHole()) { | 
 | 8445 |         Handle<NumberDictionary> new_storage = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8446 |           isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8447 |         if (!new_storage.is_identical_to(slow_storage)) { | 
 | 8448 |           slow_storage = loop_scope.CloseAndEscape(new_storage); | 
 | 8449 |         } | 
 | 8450 |       } | 
 | 8451 |     } | 
 | 8452 |     clear_storage(); | 
 | 8453 |     set_storage(*slow_storage); | 
 | 8454 |     fast_elements_ = false; | 
 | 8455 |   } | 
 | 8456 |  | 
 | 8457 |   inline void clear_storage() { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8458 |     isolate_->global_handles()->Destroy( | 
 | 8459 |         Handle<Object>::cast(storage_).location()); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8460 |   } | 
 | 8461 |  | 
 | 8462 |   inline void set_storage(FixedArray* storage) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8463 |     storage_ = Handle<FixedArray>::cast( | 
 | 8464 |         isolate_->global_handles()->Create(storage)); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8465 |   } | 
 | 8466 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8467 |   Isolate* isolate_; | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8468 |   Handle<FixedArray> storage_;  // Always a global handle. | 
 | 8469 |   // Index after last seen index. Always less than or equal to | 
 | 8470 |   // JSObject::kMaxElementCount. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8471 |   uint32_t index_offset_; | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8472 |   bool fast_elements_; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8473 | }; | 
 | 8474 |  | 
 | 8475 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8476 | static uint32_t EstimateElementCount(Handle<JSArray> array) { | 
 | 8477 |   uint32_t length = static_cast<uint32_t>(array->length()->Number()); | 
 | 8478 |   int element_count = 0; | 
 | 8479 |   switch (array->GetElementsKind()) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8480 |     case JSObject::FAST_ELEMENTS: { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8481 |       // Fast elements can't have lengths that are not representable by | 
 | 8482 |       // a 32-bit signed integer. | 
 | 8483 |       ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0); | 
 | 8484 |       int fast_length = static_cast<int>(length); | 
 | 8485 |       Handle<FixedArray> elements(FixedArray::cast(array->elements())); | 
 | 8486 |       for (int i = 0; i < fast_length; i++) { | 
 | 8487 |         if (!elements->get(i)->IsTheHole()) element_count++; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8488 |       } | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 8489 |       break; | 
 | 8490 |     } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8491 |     case JSObject::DICTIONARY_ELEMENTS: { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8492 |       Handle<NumberDictionary> dictionary( | 
 | 8493 |           NumberDictionary::cast(array->elements())); | 
 | 8494 |       int capacity = dictionary->Capacity(); | 
 | 8495 |       for (int i = 0; i < capacity; i++) { | 
 | 8496 |         Handle<Object> key(dictionary->KeyAt(i)); | 
 | 8497 |         if (dictionary->IsKey(*key)) { | 
 | 8498 |           element_count++; | 
 | 8499 |         } | 
 | 8500 |       } | 
 | 8501 |       break; | 
 | 8502 |     } | 
 | 8503 |     default: | 
 | 8504 |       // External arrays are always dense. | 
 | 8505 |       return length; | 
 | 8506 |   } | 
 | 8507 |   // As an estimate, we assume that the prototype doesn't contain any | 
 | 8508 |   // inherited elements. | 
 | 8509 |   return element_count; | 
 | 8510 | } | 
 | 8511 |  | 
 | 8512 |  | 
 | 8513 |  | 
 | 8514 | template<class ExternalArrayClass, class ElementType> | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8515 | static void IterateExternalArrayElements(Isolate* isolate, | 
 | 8516 |                                          Handle<JSObject> receiver, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8517 |                                          bool elements_are_ints, | 
 | 8518 |                                          bool elements_are_guaranteed_smis, | 
 | 8519 |                                          ArrayConcatVisitor* visitor) { | 
 | 8520 |   Handle<ExternalArrayClass> array( | 
 | 8521 |       ExternalArrayClass::cast(receiver->elements())); | 
 | 8522 |   uint32_t len = static_cast<uint32_t>(array->length()); | 
 | 8523 |  | 
 | 8524 |   ASSERT(visitor != NULL); | 
 | 8525 |   if (elements_are_ints) { | 
 | 8526 |     if (elements_are_guaranteed_smis) { | 
 | 8527 |       for (uint32_t j = 0; j < len; j++) { | 
 | 8528 |         HandleScope loop_scope; | 
 | 8529 |         Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j)))); | 
 | 8530 |         visitor->visit(j, e); | 
 | 8531 |       } | 
 | 8532 |     } else { | 
 | 8533 |       for (uint32_t j = 0; j < len; j++) { | 
 | 8534 |         HandleScope loop_scope; | 
 | 8535 |         int64_t val = static_cast<int64_t>(array->get(j)); | 
 | 8536 |         if (Smi::IsValid(static_cast<intptr_t>(val))) { | 
 | 8537 |           Handle<Smi> e(Smi::FromInt(static_cast<int>(val))); | 
 | 8538 |           visitor->visit(j, e); | 
 | 8539 |         } else { | 
 | 8540 |           Handle<Object> e = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8541 |               isolate->factory()->NewNumber(static_cast<ElementType>(val)); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8542 |           visitor->visit(j, e); | 
 | 8543 |         } | 
 | 8544 |       } | 
 | 8545 |     } | 
 | 8546 |   } else { | 
 | 8547 |     for (uint32_t j = 0; j < len; j++) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8548 |       HandleScope loop_scope(isolate); | 
 | 8549 |       Handle<Object> e = isolate->factory()->NewNumber(array->get(j)); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8550 |       visitor->visit(j, e); | 
 | 8551 |     } | 
 | 8552 |   } | 
 | 8553 | } | 
 | 8554 |  | 
 | 8555 |  | 
 | 8556 | // Used for sorting indices in a List<uint32_t>. | 
 | 8557 | static int compareUInt32(const uint32_t* ap, const uint32_t* bp) { | 
 | 8558 |   uint32_t a = *ap; | 
 | 8559 |   uint32_t b = *bp; | 
 | 8560 |   return (a == b) ? 0 : (a < b) ? -1 : 1; | 
 | 8561 | } | 
 | 8562 |  | 
 | 8563 |  | 
 | 8564 | static void CollectElementIndices(Handle<JSObject> object, | 
 | 8565 |                                   uint32_t range, | 
 | 8566 |                                   List<uint32_t>* indices) { | 
 | 8567 |   JSObject::ElementsKind kind = object->GetElementsKind(); | 
 | 8568 |   switch (kind) { | 
 | 8569 |     case JSObject::FAST_ELEMENTS: { | 
 | 8570 |       Handle<FixedArray> elements(FixedArray::cast(object->elements())); | 
 | 8571 |       uint32_t length = static_cast<uint32_t>(elements->length()); | 
 | 8572 |       if (range < length) length = range; | 
 | 8573 |       for (uint32_t i = 0; i < length; i++) { | 
 | 8574 |         if (!elements->get(i)->IsTheHole()) { | 
 | 8575 |           indices->Add(i); | 
 | 8576 |         } | 
 | 8577 |       } | 
 | 8578 |       break; | 
 | 8579 |     } | 
 | 8580 |     case JSObject::DICTIONARY_ELEMENTS: { | 
 | 8581 |       Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements())); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8582 |       uint32_t capacity = dict->Capacity(); | 
 | 8583 |       for (uint32_t j = 0; j < capacity; j++) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8584 |         HandleScope loop_scope; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8585 |         Handle<Object> k(dict->KeyAt(j)); | 
 | 8586 |         if (dict->IsKey(*k)) { | 
 | 8587 |           ASSERT(k->IsNumber()); | 
 | 8588 |           uint32_t index = static_cast<uint32_t>(k->Number()); | 
 | 8589 |           if (index < range) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8590 |             indices->Add(index); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8591 |           } | 
 | 8592 |         } | 
 | 8593 |       } | 
 | 8594 |       break; | 
 | 8595 |     } | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8596 |     default: { | 
 | 8597 |       int dense_elements_length; | 
 | 8598 |       switch (kind) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8599 |         case JSObject::EXTERNAL_PIXEL_ELEMENTS: { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8600 |         dense_elements_length = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8601 |             ExternalPixelArray::cast(object->elements())->length(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8602 |           break; | 
 | 8603 |         } | 
 | 8604 |         case JSObject::EXTERNAL_BYTE_ELEMENTS: { | 
 | 8605 |         dense_elements_length = | 
 | 8606 |             ExternalByteArray::cast(object->elements())->length(); | 
 | 8607 |           break; | 
 | 8608 |         } | 
 | 8609 |         case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { | 
 | 8610 |         dense_elements_length = | 
 | 8611 |             ExternalUnsignedByteArray::cast(object->elements())->length(); | 
 | 8612 |           break; | 
 | 8613 |         } | 
 | 8614 |         case JSObject::EXTERNAL_SHORT_ELEMENTS: { | 
 | 8615 |         dense_elements_length = | 
 | 8616 |             ExternalShortArray::cast(object->elements())->length(); | 
 | 8617 |           break; | 
 | 8618 |         } | 
 | 8619 |         case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { | 
 | 8620 |         dense_elements_length = | 
 | 8621 |             ExternalUnsignedShortArray::cast(object->elements())->length(); | 
 | 8622 |           break; | 
 | 8623 |         } | 
 | 8624 |         case JSObject::EXTERNAL_INT_ELEMENTS: { | 
 | 8625 |         dense_elements_length = | 
 | 8626 |             ExternalIntArray::cast(object->elements())->length(); | 
 | 8627 |           break; | 
 | 8628 |         } | 
 | 8629 |         case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: { | 
 | 8630 |         dense_elements_length = | 
 | 8631 |             ExternalUnsignedIntArray::cast(object->elements())->length(); | 
 | 8632 |           break; | 
 | 8633 |         } | 
 | 8634 |         case JSObject::EXTERNAL_FLOAT_ELEMENTS: { | 
 | 8635 |         dense_elements_length = | 
 | 8636 |             ExternalFloatArray::cast(object->elements())->length(); | 
 | 8637 |           break; | 
 | 8638 |         } | 
 | 8639 |         default: | 
 | 8640 |           UNREACHABLE(); | 
 | 8641 |           dense_elements_length = 0; | 
 | 8642 |           break; | 
 | 8643 |       } | 
 | 8644 |       uint32_t length = static_cast<uint32_t>(dense_elements_length); | 
 | 8645 |       if (range <= length) { | 
 | 8646 |         length = range; | 
 | 8647 |         // We will add all indices, so we might as well clear it first | 
 | 8648 |         // and avoid duplicates. | 
 | 8649 |         indices->Clear(); | 
 | 8650 |       } | 
 | 8651 |       for (uint32_t i = 0; i < length; i++) { | 
 | 8652 |         indices->Add(i); | 
 | 8653 |       } | 
 | 8654 |       if (length == range) return;  // All indices accounted for already. | 
 | 8655 |       break; | 
 | 8656 |     } | 
 | 8657 |   } | 
 | 8658 |  | 
 | 8659 |   Handle<Object> prototype(object->GetPrototype()); | 
 | 8660 |   if (prototype->IsJSObject()) { | 
 | 8661 |     // The prototype will usually have no inherited element indices, | 
 | 8662 |     // but we have to check. | 
 | 8663 |     CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices); | 
 | 8664 |   } | 
 | 8665 | } | 
 | 8666 |  | 
 | 8667 |  | 
 | 8668 | /** | 
 | 8669 |  * A helper function that visits elements of a JSArray in numerical | 
 | 8670 |  * order. | 
 | 8671 |  * | 
 | 8672 |  * The visitor argument called for each existing element in the array | 
 | 8673 |  * with the element index and the element's value. | 
 | 8674 |  * Afterwards it increments the base-index of the visitor by the array | 
 | 8675 |  * length. | 
 | 8676 |  * Returns false if any access threw an exception, otherwise true. | 
 | 8677 |  */ | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8678 | static bool IterateElements(Isolate* isolate, | 
 | 8679 |                             Handle<JSArray> receiver, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8680 |                             ArrayConcatVisitor* visitor) { | 
 | 8681 |   uint32_t length = static_cast<uint32_t>(receiver->length()->Number()); | 
 | 8682 |   switch (receiver->GetElementsKind()) { | 
 | 8683 |     case JSObject::FAST_ELEMENTS: { | 
 | 8684 |       // Run through the elements FixedArray and use HasElement and GetElement | 
 | 8685 |       // to check the prototype for missing elements. | 
 | 8686 |       Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); | 
 | 8687 |       int fast_length = static_cast<int>(length); | 
 | 8688 |       ASSERT(fast_length <= elements->length()); | 
 | 8689 |       for (int j = 0; j < fast_length; j++) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8690 |         HandleScope loop_scope(isolate); | 
 | 8691 |         Handle<Object> element_value(elements->get(j), isolate); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8692 |         if (!element_value->IsTheHole()) { | 
 | 8693 |           visitor->visit(j, element_value); | 
 | 8694 |         } else if (receiver->HasElement(j)) { | 
 | 8695 |           // Call GetElement on receiver, not its prototype, or getters won't | 
 | 8696 |           // have the correct receiver. | 
 | 8697 |           element_value = GetElement(receiver, j); | 
 | 8698 |           if (element_value.is_null()) return false; | 
 | 8699 |           visitor->visit(j, element_value); | 
 | 8700 |         } | 
 | 8701 |       } | 
 | 8702 |       break; | 
 | 8703 |     } | 
 | 8704 |     case JSObject::DICTIONARY_ELEMENTS: { | 
 | 8705 |       Handle<NumberDictionary> dict(receiver->element_dictionary()); | 
 | 8706 |       List<uint32_t> indices(dict->Capacity() / 2); | 
 | 8707 |       // Collect all indices in the object and the prototypes less | 
 | 8708 |       // than length. This might introduce duplicates in the indices list. | 
 | 8709 |       CollectElementIndices(receiver, length, &indices); | 
 | 8710 |       indices.Sort(&compareUInt32); | 
 | 8711 |       int j = 0; | 
 | 8712 |       int n = indices.length(); | 
 | 8713 |       while (j < n) { | 
 | 8714 |         HandleScope loop_scope; | 
 | 8715 |         uint32_t index = indices[j]; | 
 | 8716 |         Handle<Object> element = GetElement(receiver, index); | 
 | 8717 |         if (element.is_null()) return false; | 
 | 8718 |         visitor->visit(index, element); | 
 | 8719 |         // Skip to next different index (i.e., omit duplicates). | 
 | 8720 |         do { | 
 | 8721 |           j++; | 
 | 8722 |         } while (j < n && indices[j] == index); | 
 | 8723 |       } | 
 | 8724 |       break; | 
 | 8725 |     } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8726 |     case JSObject::EXTERNAL_PIXEL_ELEMENTS: { | 
 | 8727 |       Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast( | 
 | 8728 |           receiver->elements())); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8729 |       for (uint32_t j = 0; j < length; j++) { | 
 | 8730 |         Handle<Smi> e(Smi::FromInt(pixels->get(j))); | 
 | 8731 |         visitor->visit(j, e); | 
 | 8732 |       } | 
 | 8733 |       break; | 
 | 8734 |     } | 
 | 8735 |     case JSObject::EXTERNAL_BYTE_ELEMENTS: { | 
 | 8736 |       IterateExternalArrayElements<ExternalByteArray, int8_t>( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8737 |           isolate, receiver, true, true, visitor); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8738 |       break; | 
 | 8739 |     } | 
 | 8740 |     case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { | 
 | 8741 |       IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8742 |           isolate, receiver, true, true, visitor); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8743 |       break; | 
 | 8744 |     } | 
 | 8745 |     case JSObject::EXTERNAL_SHORT_ELEMENTS: { | 
 | 8746 |       IterateExternalArrayElements<ExternalShortArray, int16_t>( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8747 |           isolate, receiver, true, true, visitor); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8748 |       break; | 
 | 8749 |     } | 
 | 8750 |     case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { | 
 | 8751 |       IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8752 |           isolate, receiver, true, true, visitor); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8753 |       break; | 
 | 8754 |     } | 
 | 8755 |     case JSObject::EXTERNAL_INT_ELEMENTS: { | 
 | 8756 |       IterateExternalArrayElements<ExternalIntArray, int32_t>( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8757 |           isolate, receiver, true, false, visitor); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8758 |       break; | 
 | 8759 |     } | 
 | 8760 |     case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: { | 
 | 8761 |       IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8762 |           isolate, receiver, true, false, visitor); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8763 |       break; | 
 | 8764 |     } | 
 | 8765 |     case JSObject::EXTERNAL_FLOAT_ELEMENTS: { | 
 | 8766 |       IterateExternalArrayElements<ExternalFloatArray, float>( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8767 |           isolate, receiver, false, false, visitor); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8768 |       break; | 
 | 8769 |     } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8770 |     default: | 
 | 8771 |       UNREACHABLE(); | 
 | 8772 |       break; | 
 | 8773 |   } | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8774 |   visitor->increase_index_offset(length); | 
 | 8775 |   return true; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8776 | } | 
 | 8777 |  | 
 | 8778 |  | 
 | 8779 | /** | 
 | 8780 |  * Array::concat implementation. | 
 | 8781 |  * See ECMAScript 262, 15.4.4.4. | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8782 |  * TODO(581): Fix non-compliance for very large concatenations and update to | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 8783 |  * following the ECMAScript 5 specification. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8784 |  */ | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8785 | RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8786 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8787 |   HandleScope handle_scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8788 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8789 |   CONVERT_ARG_CHECKED(JSArray, arguments, 0); | 
 | 8790 |   int argument_count = static_cast<int>(arguments->length()->Number()); | 
 | 8791 |   RUNTIME_ASSERT(arguments->HasFastElements()); | 
 | 8792 |   Handle<FixedArray> elements(FixedArray::cast(arguments->elements())); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8793 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8794 |   // Pass 1: estimate the length and number of elements of the result. | 
 | 8795 |   // The actual length can be larger if any of the arguments have getters | 
 | 8796 |   // that mutate other arguments (but will otherwise be precise). | 
 | 8797 |   // The number of elements is precise if there are no inherited elements. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8798 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8799 |   uint32_t estimate_result_length = 0; | 
 | 8800 |   uint32_t estimate_nof_elements = 0; | 
 | 8801 |   { | 
 | 8802 |     for (int i = 0; i < argument_count; i++) { | 
 | 8803 |       HandleScope loop_scope; | 
 | 8804 |       Handle<Object> obj(elements->get(i)); | 
 | 8805 |       uint32_t length_estimate; | 
 | 8806 |       uint32_t element_estimate; | 
 | 8807 |       if (obj->IsJSArray()) { | 
 | 8808 |         Handle<JSArray> array(Handle<JSArray>::cast(obj)); | 
 | 8809 |         length_estimate = | 
 | 8810 |             static_cast<uint32_t>(array->length()->Number()); | 
 | 8811 |         element_estimate = | 
 | 8812 |             EstimateElementCount(array); | 
 | 8813 |       } else { | 
 | 8814 |         length_estimate = 1; | 
 | 8815 |         element_estimate = 1; | 
 | 8816 |       } | 
 | 8817 |       // Avoid overflows by capping at kMaxElementCount. | 
 | 8818 |       if (JSObject::kMaxElementCount - estimate_result_length < | 
 | 8819 |           length_estimate) { | 
 | 8820 |         estimate_result_length = JSObject::kMaxElementCount; | 
 | 8821 |       } else { | 
 | 8822 |         estimate_result_length += length_estimate; | 
 | 8823 |       } | 
 | 8824 |       if (JSObject::kMaxElementCount - estimate_nof_elements < | 
 | 8825 |           element_estimate) { | 
 | 8826 |         estimate_nof_elements = JSObject::kMaxElementCount; | 
 | 8827 |       } else { | 
 | 8828 |         estimate_nof_elements += element_estimate; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8829 |       } | 
 | 8830 |     } | 
 | 8831 |   } | 
 | 8832 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8833 |   // If estimated number of elements is more than half of length, a | 
 | 8834 |   // fixed array (fast case) is more time and space-efficient than a | 
 | 8835 |   // dictionary. | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8836 |   bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8837 |  | 
 | 8838 |   Handle<FixedArray> storage; | 
 | 8839 |   if (fast_case) { | 
 | 8840 |     // The backing storage array must have non-existing elements to | 
 | 8841 |     // preserve holes across concat operations. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8842 |     storage = isolate->factory()->NewFixedArrayWithHoles( | 
 | 8843 |         estimate_result_length); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8844 |   } else { | 
 | 8845 |     // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate | 
 | 8846 |     uint32_t at_least_space_for = estimate_nof_elements + | 
 | 8847 |                                   (estimate_nof_elements >> 2); | 
 | 8848 |     storage = Handle<FixedArray>::cast( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8849 |         isolate->factory()->NewNumberDictionary(at_least_space_for)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8850 |   } | 
 | 8851 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8852 |   ArrayConcatVisitor visitor(isolate, storage, fast_case); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8853 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8854 |   for (int i = 0; i < argument_count; i++) { | 
 | 8855 |     Handle<Object> obj(elements->get(i)); | 
 | 8856 |     if (obj->IsJSArray()) { | 
 | 8857 |       Handle<JSArray> array = Handle<JSArray>::cast(obj); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8858 |       if (!IterateElements(isolate, array, &visitor)) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8859 |         return Failure::Exception(); | 
 | 8860 |       } | 
 | 8861 |     } else { | 
 | 8862 |       visitor.visit(0, obj); | 
 | 8863 |       visitor.increase_index_offset(1); | 
 | 8864 |     } | 
 | 8865 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8866 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 8867 |   return *visitor.ToArray(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8868 | } | 
 | 8869 |  | 
 | 8870 |  | 
 | 8871 | // This will not allocate (flatten the string), but it may run | 
 | 8872 | // very slowly for very deeply nested ConsStrings.  For debugging use only. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8873 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8874 |   NoHandleAllocation ha; | 
 | 8875 |   ASSERT(args.length() == 1); | 
 | 8876 |  | 
 | 8877 |   CONVERT_CHECKED(String, string, args[0]); | 
 | 8878 |   StringInputBuffer buffer(string); | 
 | 8879 |   while (buffer.has_more()) { | 
 | 8880 |     uint16_t character = buffer.GetNext(); | 
 | 8881 |     PrintF("%c", character); | 
 | 8882 |   } | 
 | 8883 |   return string; | 
 | 8884 | } | 
 | 8885 |  | 
 | 8886 | // Moves all own elements of an object, that are below a limit, to positions | 
 | 8887 | // starting at zero. All undefined values are placed after non-undefined values, | 
 | 8888 | // and are followed by non-existing element. Does not change the length | 
 | 8889 | // property. | 
 | 8890 | // Returns the number of non-undefined elements collected. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8891 | RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8892 |   ASSERT(args.length() == 2); | 
 | 8893 |   CONVERT_CHECKED(JSObject, object, args[0]); | 
 | 8894 |   CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); | 
 | 8895 |   return object->PrepareElementsForSort(limit); | 
 | 8896 | } | 
 | 8897 |  | 
 | 8898 |  | 
 | 8899 | // Move contents of argument 0 (an array) to argument 1 (an array) | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8900 | RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8901 |   ASSERT(args.length() == 2); | 
 | 8902 |   CONVERT_CHECKED(JSArray, from, args[0]); | 
 | 8903 |   CONVERT_CHECKED(JSArray, to, args[1]); | 
| Steve Block | 8defd9f | 2010-07-08 12:39:36 +0100 | [diff] [blame] | 8904 |   HeapObject* new_elements = from->elements(); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 8905 |   MaybeObject* maybe_new_map; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8906 |   if (new_elements->map() == isolate->heap()->fixed_array_map() || | 
 | 8907 |       new_elements->map() == isolate->heap()->fixed_cow_array_map()) { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 8908 |     maybe_new_map = to->map()->GetFastElementsMap(); | 
| Steve Block | 8defd9f | 2010-07-08 12:39:36 +0100 | [diff] [blame] | 8909 |   } else { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 8910 |     maybe_new_map = to->map()->GetSlowElementsMap(); | 
| Steve Block | 8defd9f | 2010-07-08 12:39:36 +0100 | [diff] [blame] | 8911 |   } | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 8912 |   Object* new_map; | 
 | 8913 |   if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; | 
| Steve Block | 8defd9f | 2010-07-08 12:39:36 +0100 | [diff] [blame] | 8914 |   to->set_map(Map::cast(new_map)); | 
 | 8915 |   to->set_elements(new_elements); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8916 |   to->set_length(from->length()); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 8917 |   Object* obj; | 
 | 8918 |   { MaybeObject* maybe_obj = from->ResetElements(); | 
 | 8919 |     if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 
 | 8920 |   } | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 8921 |   from->set_length(Smi::FromInt(0)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8922 |   return to; | 
 | 8923 | } | 
 | 8924 |  | 
 | 8925 |  | 
| Steve Block | 5915150 | 2010-09-22 15:07:15 +0100 | [diff] [blame] | 8926 | // How many elements does this object/array have? | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8927 | RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8928 |   ASSERT(args.length() == 1); | 
| Steve Block | 5915150 | 2010-09-22 15:07:15 +0100 | [diff] [blame] | 8929 |   CONVERT_CHECKED(JSObject, object, args[0]); | 
 | 8930 |   HeapObject* elements = object->elements(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8931 |   if (elements->IsDictionary()) { | 
 | 8932 |     return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements()); | 
| Steve Block | 5915150 | 2010-09-22 15:07:15 +0100 | [diff] [blame] | 8933 |   } else if (object->IsJSArray()) { | 
 | 8934 |     return JSArray::cast(object)->length(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8935 |   } else { | 
| Steve Block | 5915150 | 2010-09-22 15:07:15 +0100 | [diff] [blame] | 8936 |     return Smi::FromInt(FixedArray::cast(elements)->length()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8937 |   } | 
 | 8938 | } | 
 | 8939 |  | 
 | 8940 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8941 | RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8942 |   HandleScope handle_scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 8943 |  | 
 | 8944 |   ASSERT_EQ(3, args.length()); | 
 | 8945 |  | 
 | 8946 |   CONVERT_ARG_CHECKED(JSObject, object, 0); | 
 | 8947 |   Handle<Object> key1 = args.at<Object>(1); | 
 | 8948 |   Handle<Object> key2 = args.at<Object>(2); | 
 | 8949 |  | 
 | 8950 |   uint32_t index1, index2; | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 8951 |   if (!key1->ToArrayIndex(&index1) | 
 | 8952 |       || !key2->ToArrayIndex(&index2)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8953 |     return isolate->ThrowIllegalOperation(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 8954 |   } | 
 | 8955 |  | 
 | 8956 |   Handle<JSObject> jsobject = Handle<JSObject>::cast(object); | 
 | 8957 |   Handle<Object> tmp1 = GetElement(jsobject, index1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8958 |   RETURN_IF_EMPTY_HANDLE(isolate, tmp1); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 8959 |   Handle<Object> tmp2 = GetElement(jsobject, index2); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8960 |   RETURN_IF_EMPTY_HANDLE(isolate, tmp2); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 8961 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8962 |   RETURN_IF_EMPTY_HANDLE(isolate, | 
 | 8963 |                          SetElement(jsobject, index1, tmp2, kStrictMode)); | 
 | 8964 |   RETURN_IF_EMPTY_HANDLE(isolate, | 
 | 8965 |                          SetElement(jsobject, index2, tmp1, kStrictMode)); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 8966 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8967 |   return isolate->heap()->undefined_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 8968 | } | 
 | 8969 |  | 
 | 8970 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8971 | // Returns an array that tells you where in the [0, length) interval an array | 
| Steve Block | 5915150 | 2010-09-22 15:07:15 +0100 | [diff] [blame] | 8972 | // might have elements.  Can either return keys (positive integers) or | 
 | 8973 | // intervals (pair of a negative integer (-start-1) followed by a | 
 | 8974 | // positive (length)) or undefined values. | 
 | 8975 | // Intervals can span over some keys that are not in the object. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 8976 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8977 |   ASSERT(args.length() == 2); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8978 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8979 |   CONVERT_ARG_CHECKED(JSObject, array, 0); | 
 | 8980 |   CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]); | 
 | 8981 |   if (array->elements()->IsDictionary()) { | 
 | 8982 |     // Create an array and get all the keys into it, then remove all the | 
 | 8983 |     // keys that are not integers in the range 0 to length-1. | 
 | 8984 |     Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS); | 
 | 8985 |     int keys_length = keys->length(); | 
 | 8986 |     for (int i = 0; i < keys_length; i++) { | 
 | 8987 |       Object* key = keys->get(i); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 8988 |       uint32_t index = 0; | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 8989 |       if (!key->ToArrayIndex(&index) || index >= length) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8990 |         // Zap invalid keys. | 
 | 8991 |         keys->set_undefined(i); | 
 | 8992 |       } | 
 | 8993 |     } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8994 |     return *isolate->factory()->NewJSArrayWithElements(keys); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8995 |   } else { | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 8996 |     ASSERT(array->HasFastElements()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 8997 |     Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 8998 |     // -1 means start of array. | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 8999 |     single_interval->set(0, Smi::FromInt(-1)); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 9000 |     uint32_t actual_length = | 
 | 9001 |         static_cast<uint32_t>(FixedArray::cast(array->elements())->length()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9002 |     uint32_t min_length = actual_length < length ? actual_length : length; | 
 | 9003 |     Handle<Object> length_object = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9004 |         isolate->factory()->NewNumber(static_cast<double>(min_length)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9005 |     single_interval->set(1, *length_object); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9006 |     return *isolate->factory()->NewJSArrayWithElements(single_interval); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9007 |   } | 
 | 9008 | } | 
 | 9009 |  | 
 | 9010 |  | 
 | 9011 | // DefineAccessor takes an optional final argument which is the | 
 | 9012 | // property attributes (eg, DONT_ENUM, DONT_DELETE).  IMPORTANT: due | 
 | 9013 | // to the way accessors are implemented, it is set for both the getter | 
 | 9014 | // and setter on the first call to DefineAccessor and ignored on | 
 | 9015 | // subsequent calls. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9016 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9017 |   RUNTIME_ASSERT(args.length() == 4 || args.length() == 5); | 
 | 9018 |   // Compute attributes. | 
 | 9019 |   PropertyAttributes attributes = NONE; | 
 | 9020 |   if (args.length() == 5) { | 
 | 9021 |     CONVERT_CHECKED(Smi, attrs, args[4]); | 
 | 9022 |     int value = attrs->value(); | 
 | 9023 |     // Only attribute bits should be set. | 
 | 9024 |     ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); | 
 | 9025 |     attributes = static_cast<PropertyAttributes>(value); | 
 | 9026 |   } | 
 | 9027 |  | 
 | 9028 |   CONVERT_CHECKED(JSObject, obj, args[0]); | 
 | 9029 |   CONVERT_CHECKED(String, name, args[1]); | 
 | 9030 |   CONVERT_CHECKED(Smi, flag, args[2]); | 
 | 9031 |   CONVERT_CHECKED(JSFunction, fun, args[3]); | 
 | 9032 |   return obj->DefineAccessor(name, flag->value() == 0, fun, attributes); | 
 | 9033 | } | 
 | 9034 |  | 
 | 9035 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9036 | RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9037 |   ASSERT(args.length() == 3); | 
 | 9038 |   CONVERT_CHECKED(JSObject, obj, args[0]); | 
 | 9039 |   CONVERT_CHECKED(String, name, args[1]); | 
 | 9040 |   CONVERT_CHECKED(Smi, flag, args[2]); | 
 | 9041 |   return obj->LookupAccessor(name, flag->value() == 0); | 
 | 9042 | } | 
 | 9043 |  | 
 | 9044 |  | 
 | 9045 | #ifdef ENABLE_DEBUGGER_SUPPORT | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9046 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9047 |   ASSERT(args.length() == 0); | 
 | 9048 |   return Execution::DebugBreakHelper(); | 
 | 9049 | } | 
 | 9050 |  | 
 | 9051 |  | 
 | 9052 | // Helper functions for wrapping and unwrapping stack frame ids. | 
 | 9053 | static Smi* WrapFrameId(StackFrame::Id id) { | 
 | 9054 |   ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4))); | 
 | 9055 |   return Smi::FromInt(id >> 2); | 
 | 9056 | } | 
 | 9057 |  | 
 | 9058 |  | 
 | 9059 | static StackFrame::Id UnwrapFrameId(Smi* wrapped) { | 
 | 9060 |   return static_cast<StackFrame::Id>(wrapped->value() << 2); | 
 | 9061 | } | 
 | 9062 |  | 
 | 9063 |  | 
 | 9064 | // Adds a JavaScript function as a debug event listener. | 
 | 9065 | // args[0]: debug event listener function to set or null or undefined for | 
 | 9066 | //          clearing the event listener function | 
 | 9067 | // args[1]: object supplied during callback | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9068 | RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9069 |   ASSERT(args.length() == 2); | 
 | 9070 |   RUNTIME_ASSERT(args[0]->IsJSFunction() || | 
 | 9071 |                  args[0]->IsUndefined() || | 
 | 9072 |                  args[0]->IsNull()); | 
 | 9073 |   Handle<Object> callback = args.at<Object>(0); | 
 | 9074 |   Handle<Object> data = args.at<Object>(1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9075 |   isolate->debugger()->SetEventListener(callback, data); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9076 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9077 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9078 | } | 
 | 9079 |  | 
 | 9080 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9081 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9082 |   ASSERT(args.length() == 0); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9083 |   isolate->stack_guard()->DebugBreak(); | 
 | 9084 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9085 | } | 
 | 9086 |  | 
 | 9087 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9088 | static MaybeObject* DebugLookupResultValue(Heap* heap, | 
 | 9089 |                                            Object* receiver, | 
 | 9090 |                                            String* name, | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 9091 |                                            LookupResult* result, | 
 | 9092 |                                            bool* caught_exception) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9093 |   Object* value; | 
 | 9094 |   switch (result->type()) { | 
 | 9095 |     case NORMAL: | 
 | 9096 |       value = result->holder()->GetNormalizedProperty(result); | 
 | 9097 |       if (value->IsTheHole()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9098 |         return heap->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9099 |       } | 
 | 9100 |       return value; | 
 | 9101 |     case FIELD: | 
 | 9102 |       value = | 
 | 9103 |           JSObject::cast( | 
 | 9104 |               result->holder())->FastPropertyAt(result->GetFieldIndex()); | 
 | 9105 |       if (value->IsTheHole()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9106 |         return heap->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9107 |       } | 
 | 9108 |       return value; | 
 | 9109 |     case CONSTANT_FUNCTION: | 
 | 9110 |       return result->GetConstantFunction(); | 
 | 9111 |     case CALLBACKS: { | 
 | 9112 |       Object* structure = result->GetCallbackObject(); | 
 | 9113 |       if (structure->IsProxy() || structure->IsAccessorInfo()) { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 9114 |         MaybeObject* maybe_value = receiver->GetPropertyWithCallback( | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9115 |             receiver, structure, name, result->holder()); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 9116 |         if (!maybe_value->ToObject(&value)) { | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 9117 |           if (maybe_value->IsRetryAfterGC()) return maybe_value; | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 9118 |           ASSERT(maybe_value->IsException()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9119 |           maybe_value = heap->isolate()->pending_exception(); | 
 | 9120 |           heap->isolate()->clear_pending_exception(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9121 |           if (caught_exception != NULL) { | 
 | 9122 |             *caught_exception = true; | 
 | 9123 |           } | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 9124 |           return maybe_value; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9125 |         } | 
 | 9126 |         return value; | 
 | 9127 |       } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9128 |         return heap->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9129 |       } | 
 | 9130 |     } | 
 | 9131 |     case INTERCEPTOR: | 
 | 9132 |     case MAP_TRANSITION: | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9133 |     case EXTERNAL_ARRAY_TRANSITION: | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9134 |     case CONSTANT_TRANSITION: | 
 | 9135 |     case NULL_DESCRIPTOR: | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9136 |       return heap->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9137 |     default: | 
 | 9138 |       UNREACHABLE(); | 
 | 9139 |   } | 
 | 9140 |   UNREACHABLE(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9141 |   return heap->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9142 | } | 
 | 9143 |  | 
 | 9144 |  | 
 | 9145 | // Get debugger related details for an object property. | 
 | 9146 | // args[0]: object holding property | 
 | 9147 | // args[1]: name of the property | 
 | 9148 | // | 
 | 9149 | // The array returned contains the following information: | 
 | 9150 | // 0: Property value | 
 | 9151 | // 1: Property details | 
 | 9152 | // 2: Property value is exception | 
 | 9153 | // 3: Getter function if defined | 
 | 9154 | // 4: Setter function if defined | 
 | 9155 | // Items 2-4 are only filled if the property has either a getter or a setter | 
 | 9156 | // defined through __defineGetter__ and/or __defineSetter__. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9157 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9158 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9159 |  | 
 | 9160 |   ASSERT(args.length() == 2); | 
 | 9161 |  | 
 | 9162 |   CONVERT_ARG_CHECKED(JSObject, obj, 0); | 
 | 9163 |   CONVERT_ARG_CHECKED(String, name, 1); | 
 | 9164 |  | 
 | 9165 |   // Make sure to set the current context to the context before the debugger was | 
 | 9166 |   // entered (if the debugger is entered). The reason for switching context here | 
 | 9167 |   // is that for some property lookups (accessors and interceptors) callbacks | 
 | 9168 |   // into the embedding application can occour, and the embedding application | 
 | 9169 |   // could have the assumption that its own global context is the current | 
 | 9170 |   // context and not some internal debugger context. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9171 |   SaveContext save(isolate); | 
 | 9172 |   if (isolate->debug()->InDebugger()) { | 
 | 9173 |     isolate->set_context(*isolate->debug()->debugger_entry()->GetContext()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9174 |   } | 
 | 9175 |  | 
 | 9176 |   // Skip the global proxy as it has no properties and always delegates to the | 
 | 9177 |   // real global object. | 
 | 9178 |   if (obj->IsJSGlobalProxy()) { | 
 | 9179 |     obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype())); | 
 | 9180 |   } | 
 | 9181 |  | 
 | 9182 |  | 
 | 9183 |   // Check if the name is trivially convertible to an index and get the element | 
 | 9184 |   // if so. | 
 | 9185 |   uint32_t index; | 
 | 9186 |   if (name->AsArrayIndex(&index)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9187 |     Handle<FixedArray> details = isolate->factory()->NewFixedArray(2); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 9188 |     Object* element_or_char; | 
 | 9189 |     { MaybeObject* maybe_element_or_char = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9190 |           Runtime::GetElementOrCharAt(isolate, obj, index); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 9191 |       if (!maybe_element_or_char->ToObject(&element_or_char)) { | 
 | 9192 |         return maybe_element_or_char; | 
 | 9193 |       } | 
 | 9194 |     } | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 9195 |     details->set(0, element_or_char); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9196 |     details->set(1, PropertyDetails(NONE, NORMAL).AsSmi()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9197 |     return *isolate->factory()->NewJSArrayWithElements(details); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9198 |   } | 
 | 9199 |  | 
 | 9200 |   // Find the number of objects making up this. | 
 | 9201 |   int length = LocalPrototypeChainLength(*obj); | 
 | 9202 |  | 
 | 9203 |   // Try local lookup on each of the objects. | 
 | 9204 |   Handle<JSObject> jsproto = obj; | 
 | 9205 |   for (int i = 0; i < length; i++) { | 
 | 9206 |     LookupResult result; | 
 | 9207 |     jsproto->LocalLookup(*name, &result); | 
 | 9208 |     if (result.IsProperty()) { | 
 | 9209 |       // LookupResult is not GC safe as it holds raw object pointers. | 
 | 9210 |       // GC can happen later in this code so put the required fields into | 
 | 9211 |       // local variables using handles when required for later use. | 
 | 9212 |       PropertyType result_type = result.type(); | 
 | 9213 |       Handle<Object> result_callback_obj; | 
 | 9214 |       if (result_type == CALLBACKS) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9215 |         result_callback_obj = Handle<Object>(result.GetCallbackObject(), | 
 | 9216 |                                              isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9217 |       } | 
 | 9218 |       Smi* property_details = result.GetPropertyDetails().AsSmi(); | 
 | 9219 |       // DebugLookupResultValue can cause GC so details from LookupResult needs | 
 | 9220 |       // to be copied to handles before this. | 
 | 9221 |       bool caught_exception = false; | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 9222 |       Object* raw_value; | 
 | 9223 |       { MaybeObject* maybe_raw_value = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9224 |             DebugLookupResultValue(isolate->heap(), *obj, *name, | 
 | 9225 |                                    &result, &caught_exception); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 9226 |         if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value; | 
 | 9227 |       } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9228 |       Handle<Object> value(raw_value, isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9229 |  | 
 | 9230 |       // If the callback object is a fixed array then it contains JavaScript | 
 | 9231 |       // getter and/or setter. | 
 | 9232 |       bool hasJavaScriptAccessors = result_type == CALLBACKS && | 
 | 9233 |                                     result_callback_obj->IsFixedArray(); | 
 | 9234 |       Handle<FixedArray> details = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9235 |           isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9236 |       details->set(0, *value); | 
 | 9237 |       details->set(1, property_details); | 
 | 9238 |       if (hasJavaScriptAccessors) { | 
 | 9239 |         details->set(2, | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9240 |                      caught_exception ? isolate->heap()->true_value() | 
 | 9241 |                                       : isolate->heap()->false_value()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9242 |         details->set(3, FixedArray::cast(*result_callback_obj)->get(0)); | 
 | 9243 |         details->set(4, FixedArray::cast(*result_callback_obj)->get(1)); | 
 | 9244 |       } | 
 | 9245 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9246 |       return *isolate->factory()->NewJSArrayWithElements(details); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9247 |     } | 
 | 9248 |     if (i < length - 1) { | 
 | 9249 |       jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); | 
 | 9250 |     } | 
 | 9251 |   } | 
 | 9252 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9253 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9254 | } | 
 | 9255 |  | 
 | 9256 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9257 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9258 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9259 |  | 
 | 9260 |   ASSERT(args.length() == 2); | 
 | 9261 |  | 
 | 9262 |   CONVERT_ARG_CHECKED(JSObject, obj, 0); | 
 | 9263 |   CONVERT_ARG_CHECKED(String, name, 1); | 
 | 9264 |  | 
 | 9265 |   LookupResult result; | 
 | 9266 |   obj->Lookup(*name, &result); | 
 | 9267 |   if (result.IsProperty()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9268 |     return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9269 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9270 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9271 | } | 
 | 9272 |  | 
 | 9273 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9274 | // Return the property type calculated from the property details. | 
 | 9275 | // args[0]: smi with property details. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9276 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9277 |   ASSERT(args.length() == 1); | 
 | 9278 |   CONVERT_CHECKED(Smi, details, args[0]); | 
 | 9279 |   PropertyType type = PropertyDetails(details).type(); | 
 | 9280 |   return Smi::FromInt(static_cast<int>(type)); | 
 | 9281 | } | 
 | 9282 |  | 
 | 9283 |  | 
 | 9284 | // Return the property attribute calculated from the property details. | 
 | 9285 | // args[0]: smi with property details. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9286 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9287 |   ASSERT(args.length() == 1); | 
 | 9288 |   CONVERT_CHECKED(Smi, details, args[0]); | 
 | 9289 |   PropertyAttributes attributes = PropertyDetails(details).attributes(); | 
 | 9290 |   return Smi::FromInt(static_cast<int>(attributes)); | 
 | 9291 | } | 
 | 9292 |  | 
 | 9293 |  | 
 | 9294 | // Return the property insertion index calculated from the property details. | 
 | 9295 | // args[0]: smi with property details. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9296 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9297 |   ASSERT(args.length() == 1); | 
 | 9298 |   CONVERT_CHECKED(Smi, details, args[0]); | 
 | 9299 |   int index = PropertyDetails(details).index(); | 
 | 9300 |   return Smi::FromInt(index); | 
 | 9301 | } | 
 | 9302 |  | 
 | 9303 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9304 | // Return property value from named interceptor. | 
 | 9305 | // args[0]: object | 
 | 9306 | // args[1]: property name | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9307 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9308 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9309 |   ASSERT(args.length() == 2); | 
 | 9310 |   CONVERT_ARG_CHECKED(JSObject, obj, 0); | 
 | 9311 |   RUNTIME_ASSERT(obj->HasNamedInterceptor()); | 
 | 9312 |   CONVERT_ARG_CHECKED(String, name, 1); | 
 | 9313 |  | 
 | 9314 |   PropertyAttributes attributes; | 
 | 9315 |   return obj->GetPropertyWithInterceptor(*obj, *name, &attributes); | 
 | 9316 | } | 
 | 9317 |  | 
 | 9318 |  | 
 | 9319 | // Return element value from indexed interceptor. | 
 | 9320 | // args[0]: object | 
 | 9321 | // args[1]: index | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9322 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9323 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9324 |   ASSERT(args.length() == 2); | 
 | 9325 |   CONVERT_ARG_CHECKED(JSObject, obj, 0); | 
 | 9326 |   RUNTIME_ASSERT(obj->HasIndexedInterceptor()); | 
 | 9327 |   CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]); | 
 | 9328 |  | 
 | 9329 |   return obj->GetElementWithInterceptor(*obj, index); | 
 | 9330 | } | 
 | 9331 |  | 
 | 9332 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9333 | RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9334 |   ASSERT(args.length() >= 1); | 
 | 9335 |   CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | 
 | 9336 |   // Check that the break id is valid. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9337 |   if (isolate->debug()->break_id() == 0 || | 
 | 9338 |       break_id != isolate->debug()->break_id()) { | 
 | 9339 |     return isolate->Throw( | 
 | 9340 |         isolate->heap()->illegal_execution_state_symbol()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9341 |   } | 
 | 9342 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9343 |   return isolate->heap()->true_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9344 | } | 
 | 9345 |  | 
 | 9346 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9347 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9348 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9349 |   ASSERT(args.length() == 1); | 
 | 9350 |  | 
 | 9351 |   // Check arguments. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 9352 |   Object* result; | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9353 |   { MaybeObject* maybe_result = Runtime_CheckExecutionState( | 
 | 9354 |       RUNTIME_ARGUMENTS(isolate, args)); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 9355 |     if (!maybe_result->ToObject(&result)) return maybe_result; | 
 | 9356 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9357 |  | 
 | 9358 |   // Count all frames which are relevant to debugging stack trace. | 
 | 9359 |   int n = 0; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9360 |   StackFrame::Id id = isolate->debug()->break_frame_id(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9361 |   if (id == StackFrame::NO_ID) { | 
 | 9362 |     // If there is no JavaScript stack frame count is 0. | 
 | 9363 |     return Smi::FromInt(0); | 
 | 9364 |   } | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9365 |   for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9366 |   return Smi::FromInt(n); | 
 | 9367 | } | 
 | 9368 |  | 
 | 9369 |  | 
 | 9370 | static const int kFrameDetailsFrameIdIndex = 0; | 
 | 9371 | static const int kFrameDetailsReceiverIndex = 1; | 
 | 9372 | static const int kFrameDetailsFunctionIndex = 2; | 
 | 9373 | static const int kFrameDetailsArgumentCountIndex = 3; | 
 | 9374 | static const int kFrameDetailsLocalCountIndex = 4; | 
 | 9375 | static const int kFrameDetailsSourcePositionIndex = 5; | 
 | 9376 | static const int kFrameDetailsConstructCallIndex = 6; | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 9377 | static const int kFrameDetailsAtReturnIndex = 7; | 
 | 9378 | static const int kFrameDetailsDebuggerFrameIndex = 8; | 
 | 9379 | static const int kFrameDetailsFirstDynamicIndex = 9; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9380 |  | 
 | 9381 | // Return an array with frame details | 
 | 9382 | // args[0]: number: break id | 
 | 9383 | // args[1]: number: frame index | 
 | 9384 | // | 
 | 9385 | // The array returned contains the following information: | 
 | 9386 | // 0: Frame id | 
 | 9387 | // 1: Receiver | 
 | 9388 | // 2: Function | 
 | 9389 | // 3: Argument count | 
 | 9390 | // 4: Local count | 
 | 9391 | // 5: Source position | 
 | 9392 | // 6: Constructor call | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 9393 | // 7: Is at return | 
 | 9394 | // 8: Debugger frame | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9395 | // Arguments name, value | 
 | 9396 | // Locals name, value | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 9397 | // Return value if any | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9398 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9399 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9400 |   ASSERT(args.length() == 2); | 
 | 9401 |  | 
 | 9402 |   // Check arguments. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 9403 |   Object* check; | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9404 |   { MaybeObject* maybe_check = Runtime_CheckExecutionState( | 
 | 9405 |       RUNTIME_ARGUMENTS(isolate, args)); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 9406 |     if (!maybe_check->ToObject(&check)) return maybe_check; | 
 | 9407 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9408 |   CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9409 |   Heap* heap = isolate->heap(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9410 |  | 
 | 9411 |   // Find the relevant frame with the requested index. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9412 |   StackFrame::Id id = isolate->debug()->break_frame_id(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9413 |   if (id == StackFrame::NO_ID) { | 
 | 9414 |     // If there are no JavaScript stack frames return undefined. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9415 |     return heap->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9416 |   } | 
 | 9417 |   int count = 0; | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9418 |   JavaScriptFrameIterator it(isolate, id); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9419 |   for (; !it.done(); it.Advance()) { | 
 | 9420 |     if (count == index) break; | 
 | 9421 |     count++; | 
 | 9422 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9423 |   if (it.done()) return heap->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9424 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 9425 |   bool is_optimized_frame = | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9426 |       it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION; | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 9427 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9428 |   // Traverse the saved contexts chain to find the active context for the | 
 | 9429 |   // selected frame. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9430 |   SaveContext* save = isolate->save_context(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9431 |   while (save != NULL && !save->below(it.frame())) { | 
 | 9432 |     save = save->prev(); | 
 | 9433 |   } | 
 | 9434 |   ASSERT(save != NULL); | 
 | 9435 |  | 
 | 9436 |   // Get the frame id. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9437 |   Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9438 |  | 
 | 9439 |   // Find source position. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9440 |   int position = | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9441 |       it.frame()->LookupCode()->SourcePosition(it.frame()->pc()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9442 |  | 
 | 9443 |   // Check for constructor frame. | 
 | 9444 |   bool constructor = it.frame()->IsConstructor(); | 
 | 9445 |  | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 9446 |   // Get scope info and read from it for local variable information. | 
 | 9447 |   Handle<JSFunction> function(JSFunction::cast(it.frame()->function())); | 
 | 9448 |   Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info()); | 
 | 9449 |   ScopeInfo<> info(*scope_info); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9450 |  | 
 | 9451 |   // Get the context. | 
 | 9452 |   Handle<Context> context(Context::cast(it.frame()->context())); | 
 | 9453 |  | 
 | 9454 |   // Get the locals names and values into a temporary array. | 
 | 9455 |   // | 
 | 9456 |   // TODO(1240907): Hide compiler-introduced stack variables | 
 | 9457 |   // (e.g. .result)?  For users of the debugger, they will probably be | 
 | 9458 |   // confusing. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9459 |   Handle<FixedArray> locals = | 
 | 9460 |       isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9461 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 9462 |   // Fill in the names of the locals. | 
 | 9463 |   for (int i = 0; i < info.NumberOfLocals(); i++) { | 
 | 9464 |     locals->set(i * 2, *info.LocalName(i)); | 
 | 9465 |   } | 
 | 9466 |  | 
 | 9467 |   // Fill in the values of the locals. | 
 | 9468 |   for (int i = 0; i < info.NumberOfLocals(); i++) { | 
 | 9469 |     if (is_optimized_frame) { | 
 | 9470 |       // If we are inspecting an optimized frame use undefined as the | 
 | 9471 |       // value for all locals. | 
 | 9472 |       // | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9473 |       // TODO(1140): We should be able to get the correct values | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 9474 |       // for locals in optimized frames. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9475 |       locals->set(i * 2 + 1, isolate->heap()->undefined_value()); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 9476 |     } else if (i < info.number_of_stack_slots()) { | 
 | 9477 |       // Get the value from the stack. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9478 |       locals->set(i * 2 + 1, it.frame()->GetExpression(i)); | 
 | 9479 |     } else { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9480 |       // Traverse the context chain to the function context as all local | 
 | 9481 |       // variables stored in the context will be on the function context. | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 9482 |       Handle<String> name = info.LocalName(i); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9483 |       while (!context->is_function_context()) { | 
 | 9484 |         context = Handle<Context>(context->previous()); | 
 | 9485 |       } | 
 | 9486 |       ASSERT(context->is_function_context()); | 
 | 9487 |       locals->set(i * 2 + 1, | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 9488 |                   context->get(scope_info->ContextSlotIndex(*name, NULL))); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9489 |     } | 
 | 9490 |   } | 
 | 9491 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 9492 |   // Check whether this frame is positioned at return. If not top | 
 | 9493 |   // frame or if the frame is optimized it cannot be at a return. | 
 | 9494 |   bool at_return = false; | 
 | 9495 |   if (!is_optimized_frame && index == 0) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9496 |     at_return = isolate->debug()->IsBreakAtReturn(it.frame()); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 9497 |   } | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 9498 |  | 
 | 9499 |   // If positioned just before return find the value to be returned and add it | 
 | 9500 |   // to the frame information. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9501 |   Handle<Object> return_value = isolate->factory()->undefined_value(); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 9502 |   if (at_return) { | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9503 |     StackFrameIterator it2(isolate); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 9504 |     Address internal_frame_sp = NULL; | 
 | 9505 |     while (!it2.done()) { | 
 | 9506 |       if (it2.frame()->is_internal()) { | 
 | 9507 |         internal_frame_sp = it2.frame()->sp(); | 
 | 9508 |       } else { | 
 | 9509 |         if (it2.frame()->is_java_script()) { | 
 | 9510 |           if (it2.frame()->id() == it.frame()->id()) { | 
 | 9511 |             // The internal frame just before the JavaScript frame contains the | 
 | 9512 |             // value to return on top. A debug break at return will create an | 
 | 9513 |             // internal frame to store the return value (eax/rax/r0) before | 
 | 9514 |             // entering the debug break exit frame. | 
 | 9515 |             if (internal_frame_sp != NULL) { | 
 | 9516 |               return_value = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9517 |                   Handle<Object>(Memory::Object_at(internal_frame_sp), | 
 | 9518 |                                  isolate); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 9519 |               break; | 
 | 9520 |             } | 
 | 9521 |           } | 
 | 9522 |         } | 
 | 9523 |  | 
 | 9524 |         // Indicate that the previous frame was not an internal frame. | 
 | 9525 |         internal_frame_sp = NULL; | 
 | 9526 |       } | 
 | 9527 |       it2.Advance(); | 
 | 9528 |     } | 
 | 9529 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9530 |  | 
 | 9531 |   // Now advance to the arguments adapter frame (if any). It contains all | 
 | 9532 |   // the provided parameters whereas the function frame always have the number | 
 | 9533 |   // of arguments matching the functions parameters. The rest of the | 
 | 9534 |   // information (except for what is collected above) is the same. | 
 | 9535 |   it.AdvanceToArgumentsFrame(); | 
 | 9536 |  | 
 | 9537 |   // Find the number of arguments to fill. At least fill the number of | 
 | 9538 |   // parameters for the function and fill more if more parameters are provided. | 
 | 9539 |   int argument_count = info.number_of_parameters(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9540 |   if (argument_count < it.frame()->ComputeParametersCount()) { | 
 | 9541 |     argument_count = it.frame()->ComputeParametersCount(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9542 |   } | 
 | 9543 |  | 
 | 9544 |   // Calculate the size of the result. | 
 | 9545 |   int details_size = kFrameDetailsFirstDynamicIndex + | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 9546 |                      2 * (argument_count + info.NumberOfLocals()) + | 
 | 9547 |                      (at_return ? 1 : 0); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9548 |   Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9549 |  | 
 | 9550 |   // Add the frame id. | 
 | 9551 |   details->set(kFrameDetailsFrameIdIndex, *frame_id); | 
 | 9552 |  | 
 | 9553 |   // Add the function (same as in function frame). | 
 | 9554 |   details->set(kFrameDetailsFunctionIndex, it.frame()->function()); | 
 | 9555 |  | 
 | 9556 |   // Add the arguments count. | 
 | 9557 |   details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count)); | 
 | 9558 |  | 
 | 9559 |   // Add the locals count | 
 | 9560 |   details->set(kFrameDetailsLocalCountIndex, | 
 | 9561 |                Smi::FromInt(info.NumberOfLocals())); | 
 | 9562 |  | 
 | 9563 |   // Add the source position. | 
 | 9564 |   if (position != RelocInfo::kNoPosition) { | 
 | 9565 |     details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position)); | 
 | 9566 |   } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9567 |     details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9568 |   } | 
 | 9569 |  | 
 | 9570 |   // Add the constructor information. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9571 |   details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9572 |  | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 9573 |   // Add the at return information. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9574 |   details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return)); | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 9575 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9576 |   // Add information on whether this frame is invoked in the debugger context. | 
 | 9577 |   details->set(kFrameDetailsDebuggerFrameIndex, | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9578 |                heap->ToBoolean(*save->context() == | 
 | 9579 |                    *isolate->debug()->debug_context())); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9580 |  | 
 | 9581 |   // Fill the dynamic part. | 
 | 9582 |   int details_index = kFrameDetailsFirstDynamicIndex; | 
 | 9583 |  | 
 | 9584 |   // Add arguments name and value. | 
 | 9585 |   for (int i = 0; i < argument_count; i++) { | 
 | 9586 |     // Name of the argument. | 
 | 9587 |     if (i < info.number_of_parameters()) { | 
 | 9588 |       details->set(details_index++, *info.parameter_name(i)); | 
 | 9589 |     } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9590 |       details->set(details_index++, heap->undefined_value()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9591 |     } | 
 | 9592 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 9593 |     // Parameter value. If we are inspecting an optimized frame, use | 
 | 9594 |     // undefined as the value. | 
 | 9595 |     // | 
 | 9596 |     // TODO(3141533): We should be able to get the actual parameter | 
 | 9597 |     // value for optimized frames. | 
 | 9598 |     if (!is_optimized_frame && | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9599 |         (i < it.frame()->ComputeParametersCount())) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9600 |       details->set(details_index++, it.frame()->GetParameter(i)); | 
 | 9601 |     } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9602 |       details->set(details_index++, heap->undefined_value()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9603 |     } | 
 | 9604 |   } | 
 | 9605 |  | 
 | 9606 |   // Add locals name and value from the temporary copy from the function frame. | 
 | 9607 |   for (int i = 0; i < info.NumberOfLocals() * 2; i++) { | 
 | 9608 |     details->set(details_index++, locals->get(i)); | 
 | 9609 |   } | 
 | 9610 |  | 
| Ben Murdoch | 7f4d5bd | 2010-06-15 11:15:29 +0100 | [diff] [blame] | 9611 |   // Add the value being returned. | 
 | 9612 |   if (at_return) { | 
 | 9613 |     details->set(details_index++, *return_value); | 
 | 9614 |   } | 
 | 9615 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9616 |   // Add the receiver (same as in function frame). | 
 | 9617 |   // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE | 
 | 9618 |   // THE FRAME ITERATOR TO WRAP THE RECEIVER. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9619 |   Handle<Object> receiver(it.frame()->receiver(), isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9620 |   if (!receiver->IsJSObject()) { | 
 | 9621 |     // If the receiver is NOT a JSObject we have hit an optimization | 
 | 9622 |     // where a value object is not converted into a wrapped JS objects. | 
 | 9623 |     // To hide this optimization from the debugger, we wrap the receiver | 
 | 9624 |     // by creating correct wrapper object based on the calling frame's | 
 | 9625 |     // global context. | 
 | 9626 |     it.Advance(); | 
 | 9627 |     Handle<Context> calling_frames_global_context( | 
 | 9628 |         Context::cast(Context::cast(it.frame()->context())->global_context())); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9629 |     receiver = | 
 | 9630 |         isolate->factory()->ToObject(receiver, calling_frames_global_context); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9631 |   } | 
 | 9632 |   details->set(kFrameDetailsReceiverIndex, *receiver); | 
 | 9633 |  | 
 | 9634 |   ASSERT_EQ(details_size, details_index); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9635 |   return *isolate->factory()->NewJSArrayWithElements(details); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9636 | } | 
 | 9637 |  | 
 | 9638 |  | 
 | 9639 | // Copy all the context locals into an object used to materialize a scope. | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9640 | static bool CopyContextLocalsToScopeObject( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9641 |     Isolate* isolate, | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 9642 |     Handle<SerializedScopeInfo> serialized_scope_info, | 
 | 9643 |     ScopeInfo<>& scope_info, | 
 | 9644 |     Handle<Context> context, | 
 | 9645 |     Handle<JSObject> scope_object) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9646 |   // Fill all context locals to the context extension. | 
 | 9647 |   for (int i = Context::MIN_CONTEXT_SLOTS; | 
 | 9648 |        i < scope_info.number_of_context_slots(); | 
 | 9649 |        i++) { | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 9650 |     int context_index = serialized_scope_info->ContextSlotIndex( | 
 | 9651 |         *scope_info.context_slot_name(i), NULL); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9652 |  | 
 | 9653 |     // Don't include the arguments shadow (.arguments) context variable. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9654 |     if (*scope_info.context_slot_name(i) != | 
 | 9655 |         isolate->heap()->arguments_shadow_symbol()) { | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9656 |       RETURN_IF_EMPTY_HANDLE_VALUE( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9657 |           isolate, | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9658 |           SetProperty(scope_object, | 
 | 9659 |                       scope_info.context_slot_name(i), | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9660 |                       Handle<Object>(context->get(context_index), isolate), | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 9661 |                       NONE, | 
 | 9662 |                       kNonStrictMode), | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9663 |           false); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9664 |     } | 
 | 9665 |   } | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9666 |  | 
 | 9667 |   return true; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9668 | } | 
 | 9669 |  | 
 | 9670 |  | 
 | 9671 | // Create a plain JSObject which materializes the local scope for the specified | 
 | 9672 | // frame. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9673 | static Handle<JSObject> MaterializeLocalScope(Isolate* isolate, | 
 | 9674 |                                               JavaScriptFrame* frame) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9675 |   Handle<JSFunction> function(JSFunction::cast(frame->function())); | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 9676 |   Handle<SharedFunctionInfo> shared(function->shared()); | 
 | 9677 |   Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info()); | 
 | 9678 |   ScopeInfo<> scope_info(*serialized_scope_info); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9679 |  | 
 | 9680 |   // Allocate and initialize a JSObject with all the arguments, stack locals | 
 | 9681 |   // heap locals and extension properties of the debugged function. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9682 |   Handle<JSObject> local_scope = | 
 | 9683 |       isolate->factory()->NewJSObject(isolate->object_function()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9684 |  | 
 | 9685 |   // First fill all parameters. | 
 | 9686 |   for (int i = 0; i < scope_info.number_of_parameters(); ++i) { | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9687 |     RETURN_IF_EMPTY_HANDLE_VALUE( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9688 |         isolate, | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9689 |         SetProperty(local_scope, | 
 | 9690 |                     scope_info.parameter_name(i), | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9691 |                     Handle<Object>(frame->GetParameter(i), isolate), | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 9692 |                     NONE, | 
 | 9693 |                     kNonStrictMode), | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9694 |         Handle<JSObject>()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9695 |   } | 
 | 9696 |  | 
 | 9697 |   // Second fill all stack locals. | 
 | 9698 |   for (int i = 0; i < scope_info.number_of_stack_slots(); i++) { | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9699 |     RETURN_IF_EMPTY_HANDLE_VALUE( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9700 |         isolate, | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9701 |         SetProperty(local_scope, | 
 | 9702 |                     scope_info.stack_slot_name(i), | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9703 |                     Handle<Object>(frame->GetExpression(i), isolate), | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 9704 |                     NONE, | 
 | 9705 |                     kNonStrictMode), | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9706 |         Handle<JSObject>()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9707 |   } | 
 | 9708 |  | 
 | 9709 |   // Third fill all context locals. | 
 | 9710 |   Handle<Context> frame_context(Context::cast(frame->context())); | 
 | 9711 |   Handle<Context> function_context(frame_context->fcontext()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9712 |   if (!CopyContextLocalsToScopeObject(isolate, | 
 | 9713 |                                       serialized_scope_info, scope_info, | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9714 |                                       function_context, local_scope)) { | 
 | 9715 |     return Handle<JSObject>(); | 
 | 9716 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9717 |  | 
 | 9718 |   // Finally copy any properties from the function context extension. This will | 
 | 9719 |   // be variables introduced by eval. | 
 | 9720 |   if (function_context->closure() == *function) { | 
 | 9721 |     if (function_context->has_extension() && | 
 | 9722 |         !function_context->IsGlobalContext()) { | 
 | 9723 |       Handle<JSObject> ext(JSObject::cast(function_context->extension())); | 
 | 9724 |       Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS); | 
 | 9725 |       for (int i = 0; i < keys->length(); i++) { | 
 | 9726 |         // Names of variables introduced by eval are strings. | 
 | 9727 |         ASSERT(keys->get(i)->IsString()); | 
 | 9728 |         Handle<String> key(String::cast(keys->get(i))); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9729 |         RETURN_IF_EMPTY_HANDLE_VALUE( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9730 |             isolate, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 9731 |             SetProperty(local_scope, | 
 | 9732 |                         key, | 
 | 9733 |                         GetProperty(ext, key), | 
 | 9734 |                         NONE, | 
 | 9735 |                         kNonStrictMode), | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9736 |             Handle<JSObject>()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9737 |       } | 
 | 9738 |     } | 
 | 9739 |   } | 
 | 9740 |   return local_scope; | 
 | 9741 | } | 
 | 9742 |  | 
 | 9743 |  | 
 | 9744 | // Create a plain JSObject which materializes the closure content for the | 
 | 9745 | // context. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9746 | static Handle<JSObject> MaterializeClosure(Isolate* isolate, | 
 | 9747 |                                            Handle<Context> context) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9748 |   ASSERT(context->is_function_context()); | 
 | 9749 |  | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 9750 |   Handle<SharedFunctionInfo> shared(context->closure()->shared()); | 
 | 9751 |   Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info()); | 
 | 9752 |   ScopeInfo<> scope_info(*serialized_scope_info); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9753 |  | 
 | 9754 |   // Allocate and initialize a JSObject with all the content of theis function | 
 | 9755 |   // closure. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9756 |   Handle<JSObject> closure_scope = | 
 | 9757 |       isolate->factory()->NewJSObject(isolate->object_function()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9758 |  | 
 | 9759 |   // Check whether the arguments shadow object exists. | 
 | 9760 |   int arguments_shadow_index = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9761 |       shared->scope_info()->ContextSlotIndex( | 
 | 9762 |           isolate->heap()->arguments_shadow_symbol(), NULL); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9763 |   if (arguments_shadow_index >= 0) { | 
 | 9764 |     // In this case all the arguments are available in the arguments shadow | 
 | 9765 |     // object. | 
 | 9766 |     Handle<JSObject> arguments_shadow( | 
 | 9767 |         JSObject::cast(context->get(arguments_shadow_index))); | 
 | 9768 |     for (int i = 0; i < scope_info.number_of_parameters(); ++i) { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 9769 |       // We don't expect exception-throwing getters on the arguments shadow. | 
 | 9770 |       Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked(); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9771 |       RETURN_IF_EMPTY_HANDLE_VALUE( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9772 |           isolate, | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9773 |           SetProperty(closure_scope, | 
 | 9774 |                       scope_info.parameter_name(i), | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9775 |                       Handle<Object>(element, isolate), | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 9776 |                       NONE, | 
 | 9777 |                       kNonStrictMode), | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9778 |           Handle<JSObject>()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9779 |     } | 
 | 9780 |   } | 
 | 9781 |  | 
 | 9782 |   // Fill all context locals to the context extension. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9783 |   if (!CopyContextLocalsToScopeObject(isolate, | 
 | 9784 |                                       serialized_scope_info, scope_info, | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9785 |                                       context, closure_scope)) { | 
 | 9786 |     return Handle<JSObject>(); | 
 | 9787 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9788 |  | 
 | 9789 |   // Finally copy any properties from the function context extension. This will | 
 | 9790 |   // be variables introduced by eval. | 
 | 9791 |   if (context->has_extension()) { | 
 | 9792 |     Handle<JSObject> ext(JSObject::cast(context->extension())); | 
 | 9793 |     Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS); | 
 | 9794 |     for (int i = 0; i < keys->length(); i++) { | 
 | 9795 |       // Names of variables introduced by eval are strings. | 
 | 9796 |       ASSERT(keys->get(i)->IsString()); | 
 | 9797 |       Handle<String> key(String::cast(keys->get(i))); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9798 |        RETURN_IF_EMPTY_HANDLE_VALUE( | 
 | 9799 |           isolate, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 9800 |           SetProperty(closure_scope, | 
 | 9801 |                       key, | 
 | 9802 |                       GetProperty(ext, key), | 
 | 9803 |                       NONE, | 
 | 9804 |                       kNonStrictMode), | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 9805 |           Handle<JSObject>()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9806 |     } | 
 | 9807 |   } | 
 | 9808 |  | 
 | 9809 |   return closure_scope; | 
 | 9810 | } | 
 | 9811 |  | 
 | 9812 |  | 
 | 9813 | // Iterate over the actual scopes visible from a stack frame. All scopes are | 
 | 9814 | // backed by an actual context except the local scope, which is inserted | 
 | 9815 | // "artifically" in the context chain. | 
 | 9816 | class ScopeIterator { | 
 | 9817 |  public: | 
 | 9818 |   enum ScopeType { | 
 | 9819 |     ScopeTypeGlobal = 0, | 
 | 9820 |     ScopeTypeLocal, | 
 | 9821 |     ScopeTypeWith, | 
 | 9822 |     ScopeTypeClosure, | 
 | 9823 |     // Every catch block contains an implicit with block (its parameter is | 
 | 9824 |     // a JSContextExtensionObject) that extends current scope with a variable | 
 | 9825 |     // holding exception object. Such with blocks are treated as scopes of their | 
 | 9826 |     // own type. | 
 | 9827 |     ScopeTypeCatch | 
 | 9828 |   }; | 
 | 9829 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9830 |   ScopeIterator(Isolate* isolate, JavaScriptFrame* frame) | 
 | 9831 |     : isolate_(isolate), | 
 | 9832 |       frame_(frame), | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9833 |       function_(JSFunction::cast(frame->function())), | 
 | 9834 |       context_(Context::cast(frame->context())), | 
 | 9835 |       local_done_(false), | 
 | 9836 |       at_local_(false) { | 
 | 9837 |  | 
 | 9838 |     // Check whether the first scope is actually a local scope. | 
 | 9839 |     if (context_->IsGlobalContext()) { | 
 | 9840 |       // If there is a stack slot for .result then this local scope has been | 
 | 9841 |       // created for evaluating top level code and it is not a real local scope. | 
 | 9842 |       // Checking for the existence of .result seems fragile, but the scope info | 
 | 9843 |       // saved with the code object does not otherwise have that information. | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 9844 |       int index = function_->shared()->scope_info()-> | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9845 |           StackSlotIndex(isolate_->heap()->result_symbol()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9846 |       at_local_ = index < 0; | 
 | 9847 |     } else if (context_->is_function_context()) { | 
 | 9848 |       at_local_ = true; | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 9849 |     } else if (context_->closure() != *function_) { | 
 | 9850 |       // The context_ is a with block from the outer function. | 
 | 9851 |       ASSERT(context_->has_extension()); | 
 | 9852 |       at_local_ = true; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9853 |     } | 
 | 9854 |   } | 
 | 9855 |  | 
 | 9856 |   // More scopes? | 
 | 9857 |   bool Done() { return context_.is_null(); } | 
 | 9858 |  | 
 | 9859 |   // Move to the next scope. | 
 | 9860 |   void Next() { | 
 | 9861 |     // If at a local scope mark the local scope as passed. | 
 | 9862 |     if (at_local_) { | 
 | 9863 |       at_local_ = false; | 
 | 9864 |       local_done_ = true; | 
 | 9865 |  | 
 | 9866 |       // If the current context is not associated with the local scope the | 
 | 9867 |       // current context is the next real scope, so don't move to the next | 
 | 9868 |       // context in this case. | 
 | 9869 |       if (context_->closure() != *function_) { | 
 | 9870 |         return; | 
 | 9871 |       } | 
 | 9872 |     } | 
 | 9873 |  | 
 | 9874 |     // The global scope is always the last in the chain. | 
 | 9875 |     if (context_->IsGlobalContext()) { | 
 | 9876 |       context_ = Handle<Context>(); | 
 | 9877 |       return; | 
 | 9878 |     } | 
 | 9879 |  | 
 | 9880 |     // Move to the next context. | 
 | 9881 |     if (context_->is_function_context()) { | 
 | 9882 |       context_ = Handle<Context>(Context::cast(context_->closure()->context())); | 
 | 9883 |     } else { | 
 | 9884 |       context_ = Handle<Context>(context_->previous()); | 
 | 9885 |     } | 
 | 9886 |  | 
 | 9887 |     // If passing the local scope indicate that the current scope is now the | 
 | 9888 |     // local scope. | 
 | 9889 |     if (!local_done_ && | 
 | 9890 |         (context_->IsGlobalContext() || (context_->is_function_context()))) { | 
 | 9891 |       at_local_ = true; | 
 | 9892 |     } | 
 | 9893 |   } | 
 | 9894 |  | 
 | 9895 |   // Return the type of the current scope. | 
 | 9896 |   int Type() { | 
 | 9897 |     if (at_local_) { | 
 | 9898 |       return ScopeTypeLocal; | 
 | 9899 |     } | 
 | 9900 |     if (context_->IsGlobalContext()) { | 
 | 9901 |       ASSERT(context_->global()->IsGlobalObject()); | 
 | 9902 |       return ScopeTypeGlobal; | 
 | 9903 |     } | 
 | 9904 |     if (context_->is_function_context()) { | 
 | 9905 |       return ScopeTypeClosure; | 
 | 9906 |     } | 
 | 9907 |     ASSERT(context_->has_extension()); | 
 | 9908 |     // Current scope is either an explicit with statement or a with statement | 
 | 9909 |     // implicitely generated for a catch block. | 
 | 9910 |     // If the extension object here is a JSContextExtensionObject then | 
 | 9911 |     // current with statement is one frome a catch block otherwise it's a | 
 | 9912 |     // regular with statement. | 
 | 9913 |     if (context_->extension()->IsJSContextExtensionObject()) { | 
 | 9914 |       return ScopeTypeCatch; | 
 | 9915 |     } | 
 | 9916 |     return ScopeTypeWith; | 
 | 9917 |   } | 
 | 9918 |  | 
 | 9919 |   // Return the JavaScript object with the content of the current scope. | 
 | 9920 |   Handle<JSObject> ScopeObject() { | 
 | 9921 |     switch (Type()) { | 
 | 9922 |       case ScopeIterator::ScopeTypeGlobal: | 
 | 9923 |         return Handle<JSObject>(CurrentContext()->global()); | 
 | 9924 |         break; | 
 | 9925 |       case ScopeIterator::ScopeTypeLocal: | 
 | 9926 |         // Materialize the content of the local scope into a JSObject. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9927 |         return MaterializeLocalScope(isolate_, frame_); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9928 |         break; | 
 | 9929 |       case ScopeIterator::ScopeTypeWith: | 
 | 9930 |       case ScopeIterator::ScopeTypeCatch: | 
 | 9931 |         // Return the with object. | 
 | 9932 |         return Handle<JSObject>(CurrentContext()->extension()); | 
 | 9933 |         break; | 
 | 9934 |       case ScopeIterator::ScopeTypeClosure: | 
 | 9935 |         // Materialize the content of the closure scope into a JSObject. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 9936 |         return MaterializeClosure(isolate_, CurrentContext()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9937 |         break; | 
 | 9938 |     } | 
 | 9939 |     UNREACHABLE(); | 
 | 9940 |     return Handle<JSObject>(); | 
 | 9941 |   } | 
 | 9942 |  | 
 | 9943 |   // Return the context for this scope. For the local context there might not | 
 | 9944 |   // be an actual context. | 
 | 9945 |   Handle<Context> CurrentContext() { | 
 | 9946 |     if (at_local_ && context_->closure() != *function_) { | 
 | 9947 |       return Handle<Context>(); | 
 | 9948 |     } | 
 | 9949 |     return context_; | 
 | 9950 |   } | 
 | 9951 |  | 
 | 9952 | #ifdef DEBUG | 
 | 9953 |   // Debug print of the content of the current scope. | 
 | 9954 |   void DebugPrint() { | 
 | 9955 |     switch (Type()) { | 
 | 9956 |       case ScopeIterator::ScopeTypeGlobal: | 
 | 9957 |         PrintF("Global:\n"); | 
 | 9958 |         CurrentContext()->Print(); | 
 | 9959 |         break; | 
 | 9960 |  | 
 | 9961 |       case ScopeIterator::ScopeTypeLocal: { | 
 | 9962 |         PrintF("Local:\n"); | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 9963 |         ScopeInfo<> scope_info(function_->shared()->scope_info()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 9964 |         scope_info.Print(); | 
 | 9965 |         if (!CurrentContext().is_null()) { | 
 | 9966 |           CurrentContext()->Print(); | 
 | 9967 |           if (CurrentContext()->has_extension()) { | 
 | 9968 |             Handle<JSObject> extension = | 
 | 9969 |                 Handle<JSObject>(CurrentContext()->extension()); | 
 | 9970 |             if (extension->IsJSContextExtensionObject()) { | 
 | 9971 |               extension->Print(); | 
 | 9972 |             } | 
 | 9973 |           } | 
 | 9974 |         } | 
 | 9975 |         break; | 
 | 9976 |       } | 
 | 9977 |  | 
 | 9978 |       case ScopeIterator::ScopeTypeWith: { | 
 | 9979 |         PrintF("With:\n"); | 
 | 9980 |         Handle<JSObject> extension = | 
 | 9981 |             Handle<JSObject>(CurrentContext()->extension()); | 
 | 9982 |         extension->Print(); | 
 | 9983 |         break; | 
 | 9984 |       } | 
 | 9985 |  | 
 | 9986 |       case ScopeIterator::ScopeTypeCatch: { | 
 | 9987 |         PrintF("Catch:\n"); | 
 | 9988 |         Handle<JSObject> extension = | 
 | 9989 |             Handle<JSObject>(CurrentContext()->extension()); | 
 | 9990 |         extension->Print(); | 
 | 9991 |         break; | 
 | 9992 |       } | 
 | 9993 |  | 
 | 9994 |       case ScopeIterator::ScopeTypeClosure: { | 
 | 9995 |         PrintF("Closure:\n"); | 
 | 9996 |         CurrentContext()->Print(); | 
 | 9997 |         if (CurrentContext()->has_extension()) { | 
 | 9998 |           Handle<JSObject> extension = | 
 | 9999 |               Handle<JSObject>(CurrentContext()->extension()); | 
 | 10000 |           if (extension->IsJSContextExtensionObject()) { | 
 | 10001 |             extension->Print(); | 
 | 10002 |           } | 
 | 10003 |         } | 
 | 10004 |         break; | 
 | 10005 |       } | 
 | 10006 |  | 
 | 10007 |       default: | 
 | 10008 |         UNREACHABLE(); | 
 | 10009 |     } | 
 | 10010 |     PrintF("\n"); | 
 | 10011 |   } | 
 | 10012 | #endif | 
 | 10013 |  | 
 | 10014 |  private: | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10015 |   Isolate* isolate_; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10016 |   JavaScriptFrame* frame_; | 
 | 10017 |   Handle<JSFunction> function_; | 
 | 10018 |   Handle<Context> context_; | 
 | 10019 |   bool local_done_; | 
 | 10020 |   bool at_local_; | 
 | 10021 |  | 
 | 10022 |   DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator); | 
 | 10023 | }; | 
 | 10024 |  | 
 | 10025 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10026 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10027 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10028 |   ASSERT(args.length() == 2); | 
 | 10029 |  | 
 | 10030 |   // Check arguments. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10031 |   Object* check; | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10032 |   { MaybeObject* maybe_check = Runtime_CheckExecutionState( | 
 | 10033 |       RUNTIME_ARGUMENTS(isolate, args)); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10034 |     if (!maybe_check->ToObject(&check)) return maybe_check; | 
 | 10035 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10036 |   CONVERT_CHECKED(Smi, wrapped_id, args[1]); | 
 | 10037 |  | 
 | 10038 |   // Get the frame where the debugging is performed. | 
 | 10039 |   StackFrame::Id id = UnwrapFrameId(wrapped_id); | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10040 |   JavaScriptFrameIterator it(isolate, id); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10041 |   JavaScriptFrame* frame = it.frame(); | 
 | 10042 |  | 
 | 10043 |   // Count the visible scopes. | 
 | 10044 |   int n = 0; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10045 |   for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10046 |     n++; | 
 | 10047 |   } | 
 | 10048 |  | 
 | 10049 |   return Smi::FromInt(n); | 
 | 10050 | } | 
 | 10051 |  | 
 | 10052 |  | 
 | 10053 | static const int kScopeDetailsTypeIndex = 0; | 
 | 10054 | static const int kScopeDetailsObjectIndex = 1; | 
 | 10055 | static const int kScopeDetailsSize = 2; | 
 | 10056 |  | 
 | 10057 | // Return an array with scope details | 
 | 10058 | // args[0]: number: break id | 
 | 10059 | // args[1]: number: frame index | 
 | 10060 | // args[2]: number: scope index | 
 | 10061 | // | 
 | 10062 | // The array returned contains the following information: | 
 | 10063 | // 0: Scope type | 
 | 10064 | // 1: Scope object | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10065 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10066 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10067 |   ASSERT(args.length() == 3); | 
 | 10068 |  | 
 | 10069 |   // Check arguments. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10070 |   Object* check; | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10071 |   { MaybeObject* maybe_check = Runtime_CheckExecutionState( | 
 | 10072 |       RUNTIME_ARGUMENTS(isolate, args)); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10073 |     if (!maybe_check->ToObject(&check)) return maybe_check; | 
 | 10074 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10075 |   CONVERT_CHECKED(Smi, wrapped_id, args[1]); | 
 | 10076 |   CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]); | 
 | 10077 |  | 
 | 10078 |   // Get the frame where the debugging is performed. | 
 | 10079 |   StackFrame::Id id = UnwrapFrameId(wrapped_id); | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10080 |   JavaScriptFrameIterator frame_it(isolate, id); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10081 |   JavaScriptFrame* frame = frame_it.frame(); | 
 | 10082 |  | 
 | 10083 |   // Find the requested scope. | 
 | 10084 |   int n = 0; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10085 |   ScopeIterator it(isolate, frame); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10086 |   for (; !it.Done() && n < index; it.Next()) { | 
 | 10087 |     n++; | 
 | 10088 |   } | 
 | 10089 |   if (it.Done()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10090 |     return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10091 |   } | 
 | 10092 |  | 
 | 10093 |   // Calculate the size of the result. | 
 | 10094 |   int details_size = kScopeDetailsSize; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10095 |   Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10096 |  | 
 | 10097 |   // Fill in scope details. | 
 | 10098 |   details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type())); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 10099 |   Handle<JSObject> scope_object = it.ScopeObject(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10100 |   RETURN_IF_EMPTY_HANDLE(isolate, scope_object); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 10101 |   details->set(kScopeDetailsObjectIndex, *scope_object); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10102 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10103 |   return *isolate->factory()->NewJSArrayWithElements(details); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10104 | } | 
 | 10105 |  | 
 | 10106 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10107 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10108 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10109 |   ASSERT(args.length() == 0); | 
 | 10110 |  | 
 | 10111 | #ifdef DEBUG | 
 | 10112 |   // Print the scopes for the top frame. | 
 | 10113 |   StackFrameLocator locator; | 
 | 10114 |   JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10115 |   for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10116 |     it.DebugPrint(); | 
 | 10117 |   } | 
 | 10118 | #endif | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10119 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10120 | } | 
 | 10121 |  | 
 | 10122 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10123 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10124 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10125 |   ASSERT(args.length() == 1); | 
 | 10126 |  | 
 | 10127 |   // Check arguments. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10128 |   Object* result; | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10129 |   { MaybeObject* maybe_result = Runtime_CheckExecutionState( | 
 | 10130 |       RUNTIME_ARGUMENTS(isolate, args)); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10131 |     if (!maybe_result->ToObject(&result)) return maybe_result; | 
 | 10132 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10133 |  | 
 | 10134 |   // Count all archived V8 threads. | 
 | 10135 |   int n = 0; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10136 |   for (ThreadState* thread = | 
 | 10137 |           isolate->thread_manager()->FirstThreadStateInUse(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10138 |        thread != NULL; | 
 | 10139 |        thread = thread->Next()) { | 
 | 10140 |     n++; | 
 | 10141 |   } | 
 | 10142 |  | 
 | 10143 |   // Total number of threads is current thread and archived threads. | 
 | 10144 |   return Smi::FromInt(n + 1); | 
 | 10145 | } | 
 | 10146 |  | 
 | 10147 |  | 
 | 10148 | static const int kThreadDetailsCurrentThreadIndex = 0; | 
 | 10149 | static const int kThreadDetailsThreadIdIndex = 1; | 
 | 10150 | static const int kThreadDetailsSize = 2; | 
 | 10151 |  | 
 | 10152 | // Return an array with thread details | 
 | 10153 | // args[0]: number: break id | 
 | 10154 | // args[1]: number: thread index | 
 | 10155 | // | 
 | 10156 | // The array returned contains the following information: | 
 | 10157 | // 0: Is current thread? | 
 | 10158 | // 1: Thread id | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10159 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10160 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10161 |   ASSERT(args.length() == 2); | 
 | 10162 |  | 
 | 10163 |   // Check arguments. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10164 |   Object* check; | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10165 |   { MaybeObject* maybe_check = Runtime_CheckExecutionState( | 
 | 10166 |       RUNTIME_ARGUMENTS(isolate, args)); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10167 |     if (!maybe_check->ToObject(&check)) return maybe_check; | 
 | 10168 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10169 |   CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); | 
 | 10170 |  | 
 | 10171 |   // Allocate array for result. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10172 |   Handle<FixedArray> details = | 
 | 10173 |       isolate->factory()->NewFixedArray(kThreadDetailsSize); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10174 |  | 
 | 10175 |   // Thread index 0 is current thread. | 
 | 10176 |   if (index == 0) { | 
 | 10177 |     // Fill the details. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10178 |     details->set(kThreadDetailsCurrentThreadIndex, | 
 | 10179 |                  isolate->heap()->true_value()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10180 |     details->set(kThreadDetailsThreadIdIndex, | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10181 |                  Smi::FromInt(ThreadId::Current().ToInteger())); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10182 |   } else { | 
 | 10183 |     // Find the thread with the requested index. | 
 | 10184 |     int n = 1; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10185 |     ThreadState* thread = | 
 | 10186 |         isolate->thread_manager()->FirstThreadStateInUse(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10187 |     while (index != n && thread != NULL) { | 
 | 10188 |       thread = thread->Next(); | 
 | 10189 |       n++; | 
 | 10190 |     } | 
 | 10191 |     if (thread == NULL) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10192 |       return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10193 |     } | 
 | 10194 |  | 
 | 10195 |     // Fill the details. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10196 |     details->set(kThreadDetailsCurrentThreadIndex, | 
 | 10197 |                  isolate->heap()->false_value()); | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10198 |     details->set(kThreadDetailsThreadIdIndex, | 
 | 10199 |                  Smi::FromInt(thread->id().ToInteger())); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10200 |   } | 
 | 10201 |  | 
 | 10202 |   // Convert to JS array and return. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10203 |   return *isolate->factory()->NewJSArrayWithElements(details); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10204 | } | 
 | 10205 |  | 
 | 10206 |  | 
| Ben Murdoch | bb769b2 | 2010-08-11 14:56:33 +0100 | [diff] [blame] | 10207 | // Sets the disable break state | 
 | 10208 | // args[0]: disable break state | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10209 | RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10210 |   HandleScope scope(isolate); | 
| Ben Murdoch | bb769b2 | 2010-08-11 14:56:33 +0100 | [diff] [blame] | 10211 |   ASSERT(args.length() == 1); | 
 | 10212 |   CONVERT_BOOLEAN_CHECKED(disable_break, args[0]); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10213 |   isolate->debug()->set_disable_break(disable_break); | 
 | 10214 |   return  isolate->heap()->undefined_value(); | 
| Ben Murdoch | bb769b2 | 2010-08-11 14:56:33 +0100 | [diff] [blame] | 10215 | } | 
 | 10216 |  | 
 | 10217 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10218 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10219 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10220 |   ASSERT(args.length() == 1); | 
 | 10221 |  | 
 | 10222 |   CONVERT_ARG_CHECKED(JSFunction, fun, 0); | 
 | 10223 |   Handle<SharedFunctionInfo> shared(fun->shared()); | 
 | 10224 |   // Find the number of break points | 
 | 10225 |   Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10226 |   if (break_locations->IsUndefined()) return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10227 |   // Return array as JS array | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10228 |   return *isolate->factory()->NewJSArrayWithElements( | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10229 |       Handle<FixedArray>::cast(break_locations)); | 
 | 10230 | } | 
 | 10231 |  | 
 | 10232 |  | 
 | 10233 | // Set a break point in a function | 
 | 10234 | // args[0]: function | 
 | 10235 | // args[1]: number: break source position (within the function source) | 
 | 10236 | // args[2]: number: break point object | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10237 | RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10238 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10239 |   ASSERT(args.length() == 3); | 
 | 10240 |   CONVERT_ARG_CHECKED(JSFunction, fun, 0); | 
 | 10241 |   Handle<SharedFunctionInfo> shared(fun->shared()); | 
 | 10242 |   CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); | 
 | 10243 |   RUNTIME_ASSERT(source_position >= 0); | 
 | 10244 |   Handle<Object> break_point_object_arg = args.at<Object>(2); | 
 | 10245 |  | 
 | 10246 |   // Set break point. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10247 |   isolate->debug()->SetBreakPoint(shared, break_point_object_arg, | 
 | 10248 |                                   &source_position); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10249 |  | 
| Steve Block | 8defd9f | 2010-07-08 12:39:36 +0100 | [diff] [blame] | 10250 |   return Smi::FromInt(source_position); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10251 | } | 
 | 10252 |  | 
 | 10253 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10254 | Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate, | 
 | 10255 |                                                 Handle<Script> script, | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10256 |                                                 int position) { | 
 | 10257 |   // Iterate the heap looking for SharedFunctionInfo generated from the | 
 | 10258 |   // script. The inner most SharedFunctionInfo containing the source position | 
 | 10259 |   // for the requested break point is found. | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 10260 |   // NOTE: This might require several heap iterations. If the SharedFunctionInfo | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10261 |   // which is found is not compiled it is compiled and the heap is iterated | 
 | 10262 |   // again as the compilation might create inner functions from the newly | 
 | 10263 |   // compiled function and the actual requested break point might be in one of | 
 | 10264 |   // these functions. | 
 | 10265 |   bool done = false; | 
 | 10266 |   // The current candidate for the source position: | 
 | 10267 |   int target_start_position = RelocInfo::kNoPosition; | 
 | 10268 |   Handle<SharedFunctionInfo> target; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10269 |   while (!done) { | 
 | 10270 |     HeapIterator iterator; | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 10271 |     for (HeapObject* obj = iterator.next(); | 
 | 10272 |          obj != NULL; obj = iterator.next()) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10273 |       if (obj->IsSharedFunctionInfo()) { | 
 | 10274 |         Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj)); | 
 | 10275 |         if (shared->script() == *script) { | 
 | 10276 |           // If the SharedFunctionInfo found has the requested script data and | 
 | 10277 |           // contains the source position it is a candidate. | 
 | 10278 |           int start_position = shared->function_token_position(); | 
 | 10279 |           if (start_position == RelocInfo::kNoPosition) { | 
 | 10280 |             start_position = shared->start_position(); | 
 | 10281 |           } | 
 | 10282 |           if (start_position <= position && | 
 | 10283 |               position <= shared->end_position()) { | 
 | 10284 |             // If there is no candidate or this function is within the current | 
 | 10285 |             // candidate this is the new candidate. | 
 | 10286 |             if (target.is_null()) { | 
 | 10287 |               target_start_position = start_position; | 
 | 10288 |               target = shared; | 
 | 10289 |             } else { | 
 | 10290 |               if (target_start_position == start_position && | 
 | 10291 |                   shared->end_position() == target->end_position()) { | 
 | 10292 |                   // If a top-level function contain only one function | 
 | 10293 |                   // declartion the source for the top-level and the function is | 
 | 10294 |                   // the same. In that case prefer the non top-level function. | 
 | 10295 |                 if (!shared->is_toplevel()) { | 
 | 10296 |                   target_start_position = start_position; | 
 | 10297 |                   target = shared; | 
 | 10298 |                 } | 
 | 10299 |               } else if (target_start_position <= start_position && | 
 | 10300 |                          shared->end_position() <= target->end_position()) { | 
 | 10301 |                 // This containment check includes equality as a function inside | 
 | 10302 |                 // a top-level function can share either start or end position | 
 | 10303 |                 // with the top-level function. | 
 | 10304 |                 target_start_position = start_position; | 
 | 10305 |                 target = shared; | 
 | 10306 |               } | 
 | 10307 |             } | 
 | 10308 |           } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10309 |         } | 
 | 10310 |       } | 
 | 10311 |     } | 
 | 10312 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10313 |     if (target.is_null()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10314 |       return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10315 |     } | 
 | 10316 |  | 
 | 10317 |     // If the candidate found is compiled we are done. NOTE: when lazy | 
 | 10318 |     // compilation of inner functions is introduced some additional checking | 
 | 10319 |     // needs to be done here to compile inner functions. | 
 | 10320 |     done = target->is_compiled(); | 
 | 10321 |     if (!done) { | 
 | 10322 |       // If the candidate is not compiled compile it to reveal any inner | 
 | 10323 |       // functions which might contain the requested source position. | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 10324 |       CompileLazyShared(target, KEEP_EXCEPTION); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10325 |     } | 
 | 10326 |   } | 
 | 10327 |  | 
 | 10328 |   return *target; | 
 | 10329 | } | 
 | 10330 |  | 
 | 10331 |  | 
| Kristian Monsen | 9dcf7e2 | 2010-06-28 14:14:28 +0100 | [diff] [blame] | 10332 | // Changes the state of a break point in a script and returns source position | 
 | 10333 | // where break point was set. NOTE: Regarding performance see the NOTE for | 
 | 10334 | // GetScriptFromScriptData. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10335 | // args[0]: script to set break point in | 
 | 10336 | // args[1]: number: break source position (within the script source) | 
 | 10337 | // args[2]: number: break point object | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10338 | RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10339 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10340 |   ASSERT(args.length() == 3); | 
 | 10341 |   CONVERT_ARG_CHECKED(JSValue, wrapper, 0); | 
 | 10342 |   CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); | 
 | 10343 |   RUNTIME_ASSERT(source_position >= 0); | 
 | 10344 |   Handle<Object> break_point_object_arg = args.at<Object>(2); | 
 | 10345 |  | 
 | 10346 |   // Get the script from the script wrapper. | 
 | 10347 |   RUNTIME_ASSERT(wrapper->value()->IsScript()); | 
 | 10348 |   Handle<Script> script(Script::cast(wrapper->value())); | 
 | 10349 |  | 
 | 10350 |   Object* result = Runtime::FindSharedFunctionInfoInScript( | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10351 |       isolate, script, source_position); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10352 |   if (!result->IsUndefined()) { | 
 | 10353 |     Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result)); | 
 | 10354 |     // Find position within function. The script position might be before the | 
 | 10355 |     // source position of the first function. | 
 | 10356 |     int position; | 
 | 10357 |     if (shared->start_position() > source_position) { | 
 | 10358 |       position = 0; | 
 | 10359 |     } else { | 
 | 10360 |       position = source_position - shared->start_position(); | 
 | 10361 |     } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10362 |     isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position); | 
| Kristian Monsen | 9dcf7e2 | 2010-06-28 14:14:28 +0100 | [diff] [blame] | 10363 |     position += shared->start_position(); | 
 | 10364 |     return Smi::FromInt(position); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10365 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10366 |   return  isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10367 | } | 
 | 10368 |  | 
 | 10369 |  | 
 | 10370 | // Clear a break point | 
 | 10371 | // args[0]: number: break point object | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10372 | RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10373 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10374 |   ASSERT(args.length() == 1); | 
 | 10375 |   Handle<Object> break_point_object_arg = args.at<Object>(0); | 
 | 10376 |  | 
 | 10377 |   // Clear break point. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10378 |   isolate->debug()->ClearBreakPoint(break_point_object_arg); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10379 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10380 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10381 | } | 
 | 10382 |  | 
 | 10383 |  | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 10384 | // Change the state of break on exceptions. | 
 | 10385 | // args[0]: Enum value indicating whether to affect caught/uncaught exceptions. | 
 | 10386 | // args[1]: Boolean indicating on/off. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10387 | RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10388 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10389 |   ASSERT(args.length() == 2); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 10390 |   RUNTIME_ASSERT(args[0]->IsNumber()); | 
 | 10391 |   CONVERT_BOOLEAN_CHECKED(enable, args[1]); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10392 |  | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 10393 |   // If the number doesn't match an enum value, the ChangeBreakOnException | 
 | 10394 |   // function will default to affecting caught exceptions. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10395 |   ExceptionBreakType type = | 
 | 10396 |       static_cast<ExceptionBreakType>(NumberToUint32(args[0])); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 10397 |   // Update break point state. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10398 |   isolate->debug()->ChangeBreakOnException(type, enable); | 
 | 10399 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10400 | } | 
 | 10401 |  | 
 | 10402 |  | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 10403 | // Returns the state of break on exceptions | 
 | 10404 | // args[0]: boolean indicating uncaught exceptions | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10405 | RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10406 |   HandleScope scope(isolate); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 10407 |   ASSERT(args.length() == 1); | 
 | 10408 |   RUNTIME_ASSERT(args[0]->IsNumber()); | 
 | 10409 |  | 
 | 10410 |   ExceptionBreakType type = | 
 | 10411 |       static_cast<ExceptionBreakType>(NumberToUint32(args[0])); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10412 |   bool result = isolate->debug()->IsBreakOnException(type); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 10413 |   return Smi::FromInt(result); | 
 | 10414 | } | 
 | 10415 |  | 
 | 10416 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10417 | // Prepare for stepping | 
 | 10418 | // args[0]: break id for checking execution state | 
 | 10419 | // args[1]: step action from the enumeration StepAction | 
 | 10420 | // args[2]: number of times to perform the step, for step out it is the number | 
 | 10421 | //          of frames to step down. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10422 | RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10423 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10424 |   ASSERT(args.length() == 3); | 
 | 10425 |   // Check arguments. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10426 |   Object* check; | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10427 |   { MaybeObject* maybe_check = Runtime_CheckExecutionState( | 
 | 10428 |       RUNTIME_ARGUMENTS(isolate, args)); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10429 |     if (!maybe_check->ToObject(&check)) return maybe_check; | 
 | 10430 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10431 |   if (!args[1]->IsNumber() || !args[2]->IsNumber()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10432 |     return isolate->Throw(isolate->heap()->illegal_argument_symbol()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10433 |   } | 
 | 10434 |  | 
 | 10435 |   // Get the step action and check validity. | 
 | 10436 |   StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1])); | 
 | 10437 |   if (step_action != StepIn && | 
 | 10438 |       step_action != StepNext && | 
 | 10439 |       step_action != StepOut && | 
 | 10440 |       step_action != StepInMin && | 
 | 10441 |       step_action != StepMin) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10442 |     return isolate->Throw(isolate->heap()->illegal_argument_symbol()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10443 |   } | 
 | 10444 |  | 
 | 10445 |   // Get the number of steps. | 
 | 10446 |   int step_count = NumberToInt32(args[2]); | 
 | 10447 |   if (step_count < 1) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10448 |     return isolate->Throw(isolate->heap()->illegal_argument_symbol()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10449 |   } | 
 | 10450 |  | 
 | 10451 |   // Clear all current stepping setup. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10452 |   isolate->debug()->ClearStepping(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10453 |  | 
 | 10454 |   // Prepare step. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10455 |   isolate->debug()->PrepareStep(static_cast<StepAction>(step_action), | 
 | 10456 |                                 step_count); | 
 | 10457 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10458 | } | 
 | 10459 |  | 
 | 10460 |  | 
 | 10461 | // Clear all stepping set by PrepareStep. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10462 | RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10463 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10464 |   ASSERT(args.length() == 0); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10465 |   isolate->debug()->ClearStepping(); | 
 | 10466 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10467 | } | 
 | 10468 |  | 
 | 10469 |  | 
 | 10470 | // Creates a copy of the with context chain. The copy of the context chain is | 
 | 10471 | // is linked to the function context supplied. | 
 | 10472 | static Handle<Context> CopyWithContextChain(Handle<Context> context_chain, | 
 | 10473 |                                             Handle<Context> function_context) { | 
 | 10474 |   // At the bottom of the chain. Return the function context to link to. | 
 | 10475 |   if (context_chain->is_function_context()) { | 
 | 10476 |     return function_context; | 
 | 10477 |   } | 
 | 10478 |  | 
 | 10479 |   // Recursively copy the with contexts. | 
 | 10480 |   Handle<Context> previous(context_chain->previous()); | 
 | 10481 |   Handle<JSObject> extension(JSObject::cast(context_chain->extension())); | 
| Steve Block | 053d10c | 2011-06-13 19:13:29 +0100 | [diff] [blame] | 10482 |   Handle<Context> context = CopyWithContextChain(function_context, previous); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10483 |   return context->GetIsolate()->factory()->NewWithContext( | 
 | 10484 |       context, extension, context_chain->IsCatchContext()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10485 | } | 
 | 10486 |  | 
 | 10487 |  | 
 | 10488 | // Helper function to find or create the arguments object for | 
 | 10489 | // Runtime_DebugEvaluate. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10490 | static Handle<Object> GetArgumentsObject(Isolate* isolate, | 
 | 10491 |                                          JavaScriptFrame* frame, | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10492 |                                          Handle<JSFunction> function, | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 10493 |                                          Handle<SerializedScopeInfo> scope_info, | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10494 |                                          const ScopeInfo<>* sinfo, | 
 | 10495 |                                          Handle<Context> function_context) { | 
 | 10496 |   // Try to find the value of 'arguments' to pass as parameter. If it is not | 
 | 10497 |   // found (that is the debugged function does not reference 'arguments' and | 
 | 10498 |   // does not support eval) then create an 'arguments' object. | 
 | 10499 |   int index; | 
 | 10500 |   if (sinfo->number_of_stack_slots() > 0) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10501 |     index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10502 |     if (index != -1) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10503 |       return Handle<Object>(frame->GetExpression(index), isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10504 |     } | 
 | 10505 |   } | 
 | 10506 |  | 
 | 10507 |   if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10508 |     index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(), | 
 | 10509 |                                          NULL); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10510 |     if (index != -1) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10511 |       return Handle<Object>(function_context->get(index), isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10512 |     } | 
 | 10513 |   } | 
 | 10514 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10515 |   const int length = frame->ComputeParametersCount(); | 
 | 10516 |   Handle<JSObject> arguments = | 
 | 10517 |       isolate->factory()->NewArgumentsObject(function, length); | 
 | 10518 |   Handle<FixedArray> array = isolate->factory()->NewFixedArray(length); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 10519 |  | 
 | 10520 |   AssertNoAllocation no_gc; | 
 | 10521 |   WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10522 |   for (int i = 0; i < length; i++) { | 
 | 10523 |     array->set(i, frame->GetParameter(i), mode); | 
 | 10524 |   } | 
 | 10525 |   arguments->set_elements(*array); | 
 | 10526 |   return arguments; | 
 | 10527 | } | 
 | 10528 |  | 
 | 10529 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10530 | static const char kSourceStr[] = | 
 | 10531 |     "(function(arguments,__source__){return eval(__source__);})"; | 
 | 10532 |  | 
 | 10533 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10534 | // Evaluate a piece of JavaScript in the context of a stack frame for | 
 | 10535 | // debugging. This is accomplished by creating a new context which in its | 
 | 10536 | // extension part has all the parameters and locals of the function on the | 
 | 10537 | // stack frame. A function which calls eval with the code to evaluate is then | 
 | 10538 | // compiled in this context and called in this context. As this context | 
 | 10539 | // replaces the context of the function on the stack frame a new (empty) | 
 | 10540 | // function is created as well to be used as the closure for the context. | 
 | 10541 | // This function and the context acts as replacements for the function on the | 
 | 10542 | // stack frame presenting the same view of the values of parameters and | 
 | 10543 | // local variables as if the piece of JavaScript was evaluated at the point | 
 | 10544 | // where the function on the stack frame is currently stopped. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10545 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10546 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10547 |  | 
 | 10548 |   // Check the execution state and decode arguments frame and source to be | 
 | 10549 |   // evaluated. | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 10550 |   ASSERT(args.length() == 5); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10551 |   Object* check_result; | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10552 |   { MaybeObject* maybe_check_result = Runtime_CheckExecutionState( | 
 | 10553 |       RUNTIME_ARGUMENTS(isolate, args)); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10554 |     if (!maybe_check_result->ToObject(&check_result)) { | 
 | 10555 |       return maybe_check_result; | 
 | 10556 |     } | 
 | 10557 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10558 |   CONVERT_CHECKED(Smi, wrapped_id, args[1]); | 
 | 10559 |   CONVERT_ARG_CHECKED(String, source, 2); | 
 | 10560 |   CONVERT_BOOLEAN_CHECKED(disable_break, args[3]); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 10561 |   Handle<Object> additional_context(args[4]); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10562 |  | 
 | 10563 |   // Handle the processing of break. | 
 | 10564 |   DisableBreak disable_break_save(disable_break); | 
 | 10565 |  | 
 | 10566 |   // Get the frame where the debugging is performed. | 
 | 10567 |   StackFrame::Id id = UnwrapFrameId(wrapped_id); | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10568 |   JavaScriptFrameIterator it(isolate, id); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10569 |   JavaScriptFrame* frame = it.frame(); | 
 | 10570 |   Handle<JSFunction> function(JSFunction::cast(frame->function())); | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 10571 |   Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info()); | 
 | 10572 |   ScopeInfo<> sinfo(*scope_info); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10573 |  | 
 | 10574 |   // Traverse the saved contexts chain to find the active context for the | 
 | 10575 |   // selected frame. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10576 |   SaveContext* save = isolate->save_context(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10577 |   while (save != NULL && !save->below(frame)) { | 
 | 10578 |     save = save->prev(); | 
 | 10579 |   } | 
 | 10580 |   ASSERT(save != NULL); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10581 |   SaveContext savex(isolate); | 
 | 10582 |   isolate->set_context(*(save->context())); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10583 |  | 
 | 10584 |   // Create the (empty) function replacing the function on the stack frame for | 
 | 10585 |   // the purpose of evaluating in the context created below. It is important | 
 | 10586 |   // that this function does not describe any parameters and local variables | 
 | 10587 |   // in the context. If it does then this will cause problems with the lookup | 
 | 10588 |   // in Context::Lookup, where context slots for parameters and local variables | 
 | 10589 |   // are looked at before the extension object. | 
 | 10590 |   Handle<JSFunction> go_between = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10591 |       isolate->factory()->NewFunction(isolate->factory()->empty_string(), | 
 | 10592 |                                       isolate->factory()->undefined_value()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10593 |   go_between->set_context(function->context()); | 
 | 10594 | #ifdef DEBUG | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 10595 |   ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10596 |   ASSERT(go_between_sinfo.number_of_parameters() == 0); | 
 | 10597 |   ASSERT(go_between_sinfo.number_of_context_slots() == 0); | 
 | 10598 | #endif | 
 | 10599 |  | 
 | 10600 |   // Materialize the content of the local scope into a JSObject. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10601 |   Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame); | 
 | 10602 |   RETURN_IF_EMPTY_HANDLE(isolate, local_scope); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10603 |  | 
 | 10604 |   // Allocate a new context for the debug evaluation and set the extension | 
 | 10605 |   // object build. | 
 | 10606 |   Handle<Context> context = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10607 |       isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS, | 
 | 10608 |                                              go_between); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10609 |   context->set_extension(*local_scope); | 
 | 10610 |   // Copy any with contexts present and chain them in front of this context. | 
 | 10611 |   Handle<Context> frame_context(Context::cast(frame->context())); | 
 | 10612 |   Handle<Context> function_context(frame_context->fcontext()); | 
 | 10613 |   context = CopyWithContextChain(frame_context, context); | 
 | 10614 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 10615 |   if (additional_context->IsJSObject()) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10616 |     context = isolate->factory()->NewWithContext(context, | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 10617 |         Handle<JSObject>::cast(additional_context), false); | 
 | 10618 |   } | 
 | 10619 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10620 |   // Wrap the evaluation statement in a new function compiled in the newly | 
 | 10621 |   // created context. The function has one parameter which has to be called | 
 | 10622 |   // 'arguments'. This it to have access to what would have been 'arguments' in | 
 | 10623 |   // the function being debugged. | 
 | 10624 |   // function(arguments,__source__) {return eval(__source__);} | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10625 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10626 |   Handle<String> function_source = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10627 |       isolate->factory()->NewStringFromAscii( | 
 | 10628 |           Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1)); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 10629 |  | 
 | 10630 |   // Currently, the eval code will be executed in non-strict mode, | 
 | 10631 |   // even in the strict code context. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 10632 |   Handle<SharedFunctionInfo> shared = | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10633 |       Compiler::CompileEval(function_source, | 
 | 10634 |                             context, | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 10635 |                             context->IsGlobalContext(), | 
 | 10636 |                             kNonStrictMode); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 10637 |   if (shared.is_null()) return Failure::Exception(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10638 |   Handle<JSFunction> compiled_function = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10639 |       isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10640 |  | 
 | 10641 |   // Invoke the result of the compilation to get the evaluation function. | 
 | 10642 |   bool has_pending_exception; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10643 |   Handle<Object> receiver(frame->receiver(), isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10644 |   Handle<Object> evaluation_function = | 
 | 10645 |       Execution::Call(compiled_function, receiver, 0, NULL, | 
 | 10646 |                       &has_pending_exception); | 
 | 10647 |   if (has_pending_exception) return Failure::Exception(); | 
 | 10648 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10649 |   Handle<Object> arguments = GetArgumentsObject(isolate, frame, | 
 | 10650 |                                                 function, scope_info, | 
| Ben Murdoch | 3bec4d2 | 2010-07-22 14:51:16 +0100 | [diff] [blame] | 10651 |                                                 &sinfo, function_context); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10652 |  | 
 | 10653 |   // Invoke the evaluation function and return the result. | 
 | 10654 |   const int argc = 2; | 
 | 10655 |   Object** argv[argc] = { arguments.location(), | 
 | 10656 |                           Handle<Object>::cast(source).location() }; | 
 | 10657 |   Handle<Object> result = | 
 | 10658 |       Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver, | 
 | 10659 |                       argc, argv, &has_pending_exception); | 
 | 10660 |   if (has_pending_exception) return Failure::Exception(); | 
 | 10661 |  | 
 | 10662 |   // Skip the global proxy as it has no properties and always delegates to the | 
 | 10663 |   // real global object. | 
 | 10664 |   if (result->IsJSGlobalProxy()) { | 
 | 10665 |     result = Handle<JSObject>(JSObject::cast(result->GetPrototype())); | 
 | 10666 |   } | 
 | 10667 |  | 
 | 10668 |   return *result; | 
 | 10669 | } | 
 | 10670 |  | 
 | 10671 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10672 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10673 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10674 |  | 
 | 10675 |   // Check the execution state and decode arguments frame and source to be | 
 | 10676 |   // evaluated. | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 10677 |   ASSERT(args.length() == 4); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10678 |   Object* check_result; | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10679 |   { MaybeObject* maybe_check_result = Runtime_CheckExecutionState( | 
 | 10680 |       RUNTIME_ARGUMENTS(isolate, args)); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10681 |     if (!maybe_check_result->ToObject(&check_result)) { | 
 | 10682 |       return maybe_check_result; | 
 | 10683 |     } | 
 | 10684 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10685 |   CONVERT_ARG_CHECKED(String, source, 1); | 
 | 10686 |   CONVERT_BOOLEAN_CHECKED(disable_break, args[2]); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 10687 |   Handle<Object> additional_context(args[3]); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10688 |  | 
 | 10689 |   // Handle the processing of break. | 
 | 10690 |   DisableBreak disable_break_save(disable_break); | 
 | 10691 |  | 
 | 10692 |   // Enter the top context from before the debugger was invoked. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10693 |   SaveContext save(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10694 |   SaveContext* top = &save; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10695 |   while (top != NULL && *top->context() == *isolate->debug()->debug_context()) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10696 |     top = top->prev(); | 
 | 10697 |   } | 
 | 10698 |   if (top != NULL) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10699 |     isolate->set_context(*top->context()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10700 |   } | 
 | 10701 |  | 
 | 10702 |   // Get the global context now set to the top context from before the | 
 | 10703 |   // debugger was invoked. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10704 |   Handle<Context> context = isolate->global_context(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10705 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 10706 |   bool is_global = true; | 
 | 10707 |  | 
 | 10708 |   if (additional_context->IsJSObject()) { | 
 | 10709 |     // Create a function context first, than put 'with' context on top of it. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10710 |     Handle<JSFunction> go_between = isolate->factory()->NewFunction( | 
 | 10711 |         isolate->factory()->empty_string(), | 
 | 10712 |         isolate->factory()->undefined_value()); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 10713 |     go_between->set_context(*context); | 
 | 10714 |     context = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10715 |         isolate->factory()->NewFunctionContext( | 
 | 10716 |             Context::MIN_CONTEXT_SLOTS, go_between); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 10717 |     context->set_extension(JSObject::cast(*additional_context)); | 
 | 10718 |     is_global = false; | 
 | 10719 |   } | 
 | 10720 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10721 |   // Compile the source to be evaluated. | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 10722 |   // Currently, the eval code will be executed in non-strict mode, | 
 | 10723 |   // even in the strict code context. | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 10724 |   Handle<SharedFunctionInfo> shared = | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 10725 |       Compiler::CompileEval(source, context, is_global, kNonStrictMode); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 10726 |   if (shared.is_null()) return Failure::Exception(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10727 |   Handle<JSFunction> compiled_function = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10728 |       Handle<JSFunction>( | 
 | 10729 |           isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, | 
 | 10730 |                                                                 context)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10731 |  | 
 | 10732 |   // Invoke the result of the compilation to get the evaluation function. | 
 | 10733 |   bool has_pending_exception; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10734 |   Handle<Object> receiver = isolate->global(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10735 |   Handle<Object> result = | 
 | 10736 |     Execution::Call(compiled_function, receiver, 0, NULL, | 
 | 10737 |                     &has_pending_exception); | 
 | 10738 |   if (has_pending_exception) return Failure::Exception(); | 
 | 10739 |   return *result; | 
 | 10740 | } | 
 | 10741 |  | 
 | 10742 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10743 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10744 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10745 |   ASSERT(args.length() == 0); | 
 | 10746 |  | 
 | 10747 |   // Fill the script objects. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10748 |   Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10749 |  | 
 | 10750 |   // Convert the script objects to proper JS objects. | 
 | 10751 |   for (int i = 0; i < instances->length(); i++) { | 
 | 10752 |     Handle<Script> script = Handle<Script>(Script::cast(instances->get(i))); | 
 | 10753 |     // Get the script wrapper in a local handle before calling GetScriptWrapper, | 
 | 10754 |     // because using | 
 | 10755 |     //   instances->set(i, *GetScriptWrapper(script)) | 
 | 10756 |     // is unsafe as GetScriptWrapper might call GC and the C++ compiler might | 
 | 10757 |     // already have deferenced the instances handle. | 
 | 10758 |     Handle<JSValue> wrapper = GetScriptWrapper(script); | 
 | 10759 |     instances->set(i, *wrapper); | 
 | 10760 |   } | 
 | 10761 |  | 
 | 10762 |   // Return result as a JS array. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10763 |   Handle<JSObject> result = | 
 | 10764 |       isolate->factory()->NewJSObject(isolate->array_function()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10765 |   Handle<JSArray>::cast(result)->SetContent(*instances); | 
 | 10766 |   return *result; | 
 | 10767 | } | 
 | 10768 |  | 
 | 10769 |  | 
 | 10770 | // Helper function used by Runtime_DebugReferencedBy below. | 
 | 10771 | static int DebugReferencedBy(JSObject* target, | 
 | 10772 |                              Object* instance_filter, int max_references, | 
 | 10773 |                              FixedArray* instances, int instances_size, | 
 | 10774 |                              JSFunction* arguments_function) { | 
 | 10775 |   NoHandleAllocation ha; | 
 | 10776 |   AssertNoAllocation no_alloc; | 
 | 10777 |  | 
 | 10778 |   // Iterate the heap. | 
 | 10779 |   int count = 0; | 
 | 10780 |   JSObject* last = NULL; | 
 | 10781 |   HeapIterator iterator; | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 10782 |   HeapObject* heap_obj = NULL; | 
 | 10783 |   while (((heap_obj = iterator.next()) != NULL) && | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10784 |          (max_references == 0 || count < max_references)) { | 
 | 10785 |     // Only look at all JSObjects. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10786 |     if (heap_obj->IsJSObject()) { | 
 | 10787 |       // Skip context extension objects and argument arrays as these are | 
 | 10788 |       // checked in the context of functions using them. | 
 | 10789 |       JSObject* obj = JSObject::cast(heap_obj); | 
 | 10790 |       if (obj->IsJSContextExtensionObject() || | 
 | 10791 |           obj->map()->constructor() == arguments_function) { | 
 | 10792 |         continue; | 
 | 10793 |       } | 
 | 10794 |  | 
 | 10795 |       // Check if the JS object has a reference to the object looked for. | 
 | 10796 |       if (obj->ReferencesObject(target)) { | 
 | 10797 |         // Check instance filter if supplied. This is normally used to avoid | 
 | 10798 |         // references from mirror objects (see Runtime_IsInPrototypeChain). | 
 | 10799 |         if (!instance_filter->IsUndefined()) { | 
 | 10800 |           Object* V = obj; | 
 | 10801 |           while (true) { | 
 | 10802 |             Object* prototype = V->GetPrototype(); | 
 | 10803 |             if (prototype->IsNull()) { | 
 | 10804 |               break; | 
 | 10805 |             } | 
 | 10806 |             if (instance_filter == prototype) { | 
 | 10807 |               obj = NULL;  // Don't add this object. | 
 | 10808 |               break; | 
 | 10809 |             } | 
 | 10810 |             V = prototype; | 
 | 10811 |           } | 
 | 10812 |         } | 
 | 10813 |  | 
 | 10814 |         if (obj != NULL) { | 
 | 10815 |           // Valid reference found add to instance array if supplied an update | 
 | 10816 |           // count. | 
 | 10817 |           if (instances != NULL && count < instances_size) { | 
 | 10818 |             instances->set(count, obj); | 
 | 10819 |           } | 
 | 10820 |           last = obj; | 
 | 10821 |           count++; | 
 | 10822 |         } | 
 | 10823 |       } | 
 | 10824 |     } | 
 | 10825 |   } | 
 | 10826 |  | 
 | 10827 |   // Check for circular reference only. This can happen when the object is only | 
 | 10828 |   // referenced from mirrors and has a circular reference in which case the | 
 | 10829 |   // object is not really alive and would have been garbage collected if not | 
 | 10830 |   // referenced from the mirror. | 
 | 10831 |   if (count == 1 && last == target) { | 
 | 10832 |     count = 0; | 
 | 10833 |   } | 
 | 10834 |  | 
 | 10835 |   // Return the number of referencing objects found. | 
 | 10836 |   return count; | 
 | 10837 | } | 
 | 10838 |  | 
 | 10839 |  | 
 | 10840 | // Scan the heap for objects with direct references to an object | 
 | 10841 | // args[0]: the object to find references to | 
 | 10842 | // args[1]: constructor function for instances to exclude (Mirror) | 
 | 10843 | // args[2]: the the maximum number of objects to return | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10844 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10845 |   ASSERT(args.length() == 3); | 
 | 10846 |  | 
 | 10847 |   // First perform a full GC in order to avoid references from dead objects. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10848 |   isolate->heap()->CollectAllGarbage(false); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10849 |  | 
 | 10850 |   // Check parameters. | 
 | 10851 |   CONVERT_CHECKED(JSObject, target, args[0]); | 
 | 10852 |   Object* instance_filter = args[1]; | 
 | 10853 |   RUNTIME_ASSERT(instance_filter->IsUndefined() || | 
 | 10854 |                  instance_filter->IsJSObject()); | 
 | 10855 |   CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]); | 
 | 10856 |   RUNTIME_ASSERT(max_references >= 0); | 
 | 10857 |  | 
 | 10858 |   // Get the constructor function for context extension and arguments array. | 
 | 10859 |   JSObject* arguments_boilerplate = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10860 |       isolate->context()->global_context()->arguments_boilerplate(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10861 |   JSFunction* arguments_function = | 
 | 10862 |       JSFunction::cast(arguments_boilerplate->map()->constructor()); | 
 | 10863 |  | 
 | 10864 |   // Get the number of referencing objects. | 
 | 10865 |   int count; | 
 | 10866 |   count = DebugReferencedBy(target, instance_filter, max_references, | 
 | 10867 |                             NULL, 0, arguments_function); | 
 | 10868 |  | 
 | 10869 |   // Allocate an array to hold the result. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10870 |   Object* object; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10871 |   { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10872 |     if (!maybe_object->ToObject(&object)) return maybe_object; | 
 | 10873 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10874 |   FixedArray* instances = FixedArray::cast(object); | 
 | 10875 |  | 
 | 10876 |   // Fill the referencing objects. | 
 | 10877 |   count = DebugReferencedBy(target, instance_filter, max_references, | 
 | 10878 |                             instances, count, arguments_function); | 
 | 10879 |  | 
 | 10880 |   // Return result as JS array. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10881 |   Object* result; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10882 |   { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject( | 
 | 10883 |       isolate->context()->global_context()->array_function()); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10884 |     if (!maybe_result->ToObject(&result)) return maybe_result; | 
 | 10885 |   } | 
 | 10886 |   JSArray::cast(result)->SetContent(instances); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10887 |   return result; | 
 | 10888 | } | 
 | 10889 |  | 
 | 10890 |  | 
 | 10891 | // Helper function used by Runtime_DebugConstructedBy below. | 
 | 10892 | static int DebugConstructedBy(JSFunction* constructor, int max_references, | 
 | 10893 |                               FixedArray* instances, int instances_size) { | 
 | 10894 |   AssertNoAllocation no_alloc; | 
 | 10895 |  | 
 | 10896 |   // Iterate the heap. | 
 | 10897 |   int count = 0; | 
 | 10898 |   HeapIterator iterator; | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 10899 |   HeapObject* heap_obj = NULL; | 
 | 10900 |   while (((heap_obj = iterator.next()) != NULL) && | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10901 |          (max_references == 0 || count < max_references)) { | 
 | 10902 |     // Only look at all JSObjects. | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10903 |     if (heap_obj->IsJSObject()) { | 
 | 10904 |       JSObject* obj = JSObject::cast(heap_obj); | 
 | 10905 |       if (obj->map()->constructor() == constructor) { | 
 | 10906 |         // Valid reference found add to instance array if supplied an update | 
 | 10907 |         // count. | 
 | 10908 |         if (instances != NULL && count < instances_size) { | 
 | 10909 |           instances->set(count, obj); | 
 | 10910 |         } | 
 | 10911 |         count++; | 
 | 10912 |       } | 
 | 10913 |     } | 
 | 10914 |   } | 
 | 10915 |  | 
 | 10916 |   // Return the number of referencing objects found. | 
 | 10917 |   return count; | 
 | 10918 | } | 
 | 10919 |  | 
 | 10920 |  | 
 | 10921 | // Scan the heap for objects constructed by a specific function. | 
 | 10922 | // args[0]: the constructor to find instances of | 
 | 10923 | // args[1]: the the maximum number of objects to return | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10924 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10925 |   ASSERT(args.length() == 2); | 
 | 10926 |  | 
 | 10927 |   // First perform a full GC in order to avoid dead objects. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10928 |   isolate->heap()->CollectAllGarbage(false); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10929 |  | 
 | 10930 |   // Check parameters. | 
 | 10931 |   CONVERT_CHECKED(JSFunction, constructor, args[0]); | 
 | 10932 |   CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]); | 
 | 10933 |   RUNTIME_ASSERT(max_references >= 0); | 
 | 10934 |  | 
 | 10935 |   // Get the number of referencing objects. | 
 | 10936 |   int count; | 
 | 10937 |   count = DebugConstructedBy(constructor, max_references, NULL, 0); | 
 | 10938 |  | 
 | 10939 |   // Allocate an array to hold the result. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10940 |   Object* object; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10941 |   { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10942 |     if (!maybe_object->ToObject(&object)) return maybe_object; | 
 | 10943 |   } | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10944 |   FixedArray* instances = FixedArray::cast(object); | 
 | 10945 |  | 
 | 10946 |   // Fill the referencing objects. | 
 | 10947 |   count = DebugConstructedBy(constructor, max_references, instances, count); | 
 | 10948 |  | 
 | 10949 |   // Return result as JS array. | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10950 |   Object* result; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10951 |   { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject( | 
 | 10952 |           isolate->context()->global_context()->array_function()); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 10953 |     if (!maybe_result->ToObject(&result)) return maybe_result; | 
 | 10954 |   } | 
 | 10955 |   JSArray::cast(result)->SetContent(instances); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10956 |   return result; | 
 | 10957 | } | 
 | 10958 |  | 
 | 10959 |  | 
 | 10960 | // Find the effective prototype object as returned by __proto__. | 
 | 10961 | // args[0]: the object to find the prototype for. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10962 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10963 |   ASSERT(args.length() == 1); | 
 | 10964 |  | 
 | 10965 |   CONVERT_CHECKED(JSObject, obj, args[0]); | 
 | 10966 |  | 
 | 10967 |   // Use the __proto__ accessor. | 
 | 10968 |   return Accessors::ObjectPrototype.getter(obj, NULL); | 
 | 10969 | } | 
 | 10970 |  | 
 | 10971 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10972 | RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10973 |   ASSERT(args.length() == 0); | 
 | 10974 |   CPU::DebugBreak(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10975 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10976 | } | 
 | 10977 |  | 
 | 10978 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10979 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10980 | #ifdef DEBUG | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10981 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10982 |   ASSERT(args.length() == 1); | 
 | 10983 |   // Get the function and make sure it is compiled. | 
 | 10984 |   CONVERT_ARG_CHECKED(JSFunction, func, 0); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 10985 |   Handle<SharedFunctionInfo> shared(func->shared()); | 
 | 10986 |   if (!EnsureCompiled(shared, KEEP_EXCEPTION)) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10987 |     return Failure::Exception(); | 
 | 10988 |   } | 
 | 10989 |   func->code()->PrintLn(); | 
 | 10990 | #endif  // DEBUG | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10991 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10992 | } | 
 | 10993 |  | 
 | 10994 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 10995 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10996 | #ifdef DEBUG | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 10997 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 10998 |   ASSERT(args.length() == 1); | 
 | 10999 |   // Get the function and make sure it is compiled. | 
 | 11000 |   CONVERT_ARG_CHECKED(JSFunction, func, 0); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 11001 |   Handle<SharedFunctionInfo> shared(func->shared()); | 
 | 11002 |   if (!EnsureCompiled(shared, KEEP_EXCEPTION)) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11003 |     return Failure::Exception(); | 
 | 11004 |   } | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 11005 |   shared->construct_stub()->PrintLn(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11006 | #endif  // DEBUG | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11007 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11008 | } | 
 | 11009 |  | 
 | 11010 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11011 | RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11012 |   NoHandleAllocation ha; | 
 | 11013 |   ASSERT(args.length() == 1); | 
 | 11014 |  | 
 | 11015 |   CONVERT_CHECKED(JSFunction, f, args[0]); | 
 | 11016 |   return f->shared()->inferred_name(); | 
 | 11017 | } | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 11018 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11019 |  | 
 | 11020 | static int FindSharedFunctionInfosForScript(Script* script, | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11021 |                                             FixedArray* buffer) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11022 |   AssertNoAllocation no_allocations; | 
 | 11023 |  | 
 | 11024 |   int counter = 0; | 
 | 11025 |   int buffer_size = buffer->length(); | 
 | 11026 |   HeapIterator iterator; | 
 | 11027 |   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { | 
 | 11028 |     ASSERT(obj != NULL); | 
 | 11029 |     if (!obj->IsSharedFunctionInfo()) { | 
 | 11030 |       continue; | 
 | 11031 |     } | 
 | 11032 |     SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); | 
 | 11033 |     if (shared->script() != script) { | 
 | 11034 |       continue; | 
 | 11035 |     } | 
 | 11036 |     if (counter < buffer_size) { | 
 | 11037 |       buffer->set(counter, shared); | 
 | 11038 |     } | 
 | 11039 |     counter++; | 
 | 11040 |   } | 
 | 11041 |   return counter; | 
 | 11042 | } | 
 | 11043 |  | 
 | 11044 | // For a script finds all SharedFunctionInfo's in the heap that points | 
 | 11045 | // to this script. Returns JSArray of SharedFunctionInfo wrapped | 
 | 11046 | // in OpaqueReferences. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11047 | RUNTIME_FUNCTION(MaybeObject*, | 
 | 11048 |                  Runtime_LiveEditFindSharedFunctionInfosForScript) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11049 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11050 |   HandleScope scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11051 |   CONVERT_CHECKED(JSValue, script_value, args[0]); | 
 | 11052 |  | 
 | 11053 |   Handle<Script> script = Handle<Script>(Script::cast(script_value->value())); | 
 | 11054 |  | 
 | 11055 |   const int kBufferSize = 32; | 
 | 11056 |  | 
 | 11057 |   Handle<FixedArray> array; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11058 |   array = isolate->factory()->NewFixedArray(kBufferSize); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11059 |   int number = FindSharedFunctionInfosForScript(*script, *array); | 
 | 11060 |   if (number > kBufferSize) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11061 |     array = isolate->factory()->NewFixedArray(number); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11062 |     FindSharedFunctionInfosForScript(*script, *array); | 
 | 11063 |   } | 
 | 11064 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11065 |   Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11066 |   result->set_length(Smi::FromInt(number)); | 
 | 11067 |  | 
 | 11068 |   LiveEdit::WrapSharedFunctionInfos(result); | 
 | 11069 |  | 
 | 11070 |   return *result; | 
 | 11071 | } | 
 | 11072 |  | 
 | 11073 | // For a script calculates compilation information about all its functions. | 
 | 11074 | // The script source is explicitly specified by the second argument. | 
 | 11075 | // The source of the actual script is not used, however it is important that | 
 | 11076 | // all generated code keeps references to this particular instance of script. | 
 | 11077 | // Returns a JSArray of compilation infos. The array is ordered so that | 
 | 11078 | // each function with all its descendant is always stored in a continues range | 
 | 11079 | // with the function itself going first. The root function is a script function. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11080 | RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11081 |   ASSERT(args.length() == 2); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11082 |   HandleScope scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11083 |   CONVERT_CHECKED(JSValue, script, args[0]); | 
 | 11084 |   CONVERT_ARG_CHECKED(String, source, 1); | 
 | 11085 |   Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); | 
 | 11086 |  | 
 | 11087 |   JSArray* result =  LiveEdit::GatherCompileInfo(script_handle, source); | 
 | 11088 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11089 |   if (isolate->has_pending_exception()) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11090 |     return Failure::Exception(); | 
 | 11091 |   } | 
 | 11092 |  | 
 | 11093 |   return result; | 
 | 11094 | } | 
 | 11095 |  | 
 | 11096 | // Changes the source of the script to a new_source. | 
 | 11097 | // If old_script_name is provided (i.e. is a String), also creates a copy of | 
 | 11098 | // the script with its original source and sends notification to debugger. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11099 | RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11100 |   ASSERT(args.length() == 3); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11101 |   HandleScope scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11102 |   CONVERT_CHECKED(JSValue, original_script_value, args[0]); | 
 | 11103 |   CONVERT_ARG_CHECKED(String, new_source, 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11104 |   Handle<Object> old_script_name(args[2], isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11105 |  | 
 | 11106 |   CONVERT_CHECKED(Script, original_script_pointer, | 
 | 11107 |                   original_script_value->value()); | 
 | 11108 |   Handle<Script> original_script(original_script_pointer); | 
 | 11109 |  | 
 | 11110 |   Object* old_script = LiveEdit::ChangeScriptSource(original_script, | 
 | 11111 |                                                     new_source, | 
 | 11112 |                                                     old_script_name); | 
 | 11113 |  | 
 | 11114 |   if (old_script->IsScript()) { | 
 | 11115 |     Handle<Script> script_handle(Script::cast(old_script)); | 
 | 11116 |     return *(GetScriptWrapper(script_handle)); | 
 | 11117 |   } else { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11118 |     return isolate->heap()->null_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11119 |   } | 
 | 11120 | } | 
 | 11121 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 11122 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11123 | RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) { | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 11124 |   ASSERT(args.length() == 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11125 |   HandleScope scope(isolate); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 11126 |   CONVERT_ARG_CHECKED(JSArray, shared_info, 0); | 
 | 11127 |   return LiveEdit::FunctionSourceUpdated(shared_info); | 
 | 11128 | } | 
 | 11129 |  | 
 | 11130 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11131 | // Replaces code of SharedFunctionInfo with a new one. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11132 | RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11133 |   ASSERT(args.length() == 2); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11134 |   HandleScope scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11135 |   CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0); | 
 | 11136 |   CONVERT_ARG_CHECKED(JSArray, shared_info, 1); | 
 | 11137 |  | 
 | 11138 |   return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info); | 
 | 11139 | } | 
 | 11140 |  | 
 | 11141 | // Connects SharedFunctionInfo to another script. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11142 | RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11143 |   ASSERT(args.length() == 2); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11144 |   HandleScope scope(isolate); | 
 | 11145 |   Handle<Object> function_object(args[0], isolate); | 
 | 11146 |   Handle<Object> script_object(args[1], isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11147 |  | 
 | 11148 |   if (function_object->IsJSValue()) { | 
 | 11149 |     Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object); | 
 | 11150 |     if (script_object->IsJSValue()) { | 
 | 11151 |       CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11152 |       script_object = Handle<Object>(script, isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11153 |     } | 
 | 11154 |  | 
 | 11155 |     LiveEdit::SetFunctionScript(function_wrapper, script_object); | 
 | 11156 |   } else { | 
 | 11157 |     // Just ignore this. We may not have a SharedFunctionInfo for some functions | 
 | 11158 |     // and we check it in this function. | 
 | 11159 |   } | 
 | 11160 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11161 |   return isolate->heap()->undefined_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11162 | } | 
 | 11163 |  | 
 | 11164 |  | 
 | 11165 | // In a code of a parent function replaces original function as embedded object | 
 | 11166 | // with a substitution one. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11167 | RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11168 |   ASSERT(args.length() == 3); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11169 |   HandleScope scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11170 |  | 
 | 11171 |   CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0); | 
 | 11172 |   CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1); | 
 | 11173 |   CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2); | 
 | 11174 |  | 
 | 11175 |   LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper, | 
 | 11176 |                                        subst_wrapper); | 
 | 11177 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11178 |   return isolate->heap()->undefined_value(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11179 | } | 
 | 11180 |  | 
 | 11181 |  | 
 | 11182 | // Updates positions of a shared function info (first parameter) according | 
 | 11183 | // to script source change. Text change is described in second parameter as | 
 | 11184 | // array of groups of 3 numbers: | 
 | 11185 | // (change_begin, change_end, change_end_new_position). | 
 | 11186 | // Each group describes a change in text; groups are sorted by change_begin. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11187 | RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11188 |   ASSERT(args.length() == 2); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11189 |   HandleScope scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11190 |   CONVERT_ARG_CHECKED(JSArray, shared_array, 0); | 
 | 11191 |   CONVERT_ARG_CHECKED(JSArray, position_change_array, 1); | 
 | 11192 |  | 
 | 11193 |   return LiveEdit::PatchFunctionPositions(shared_array, position_change_array); | 
 | 11194 | } | 
 | 11195 |  | 
 | 11196 |  | 
 | 11197 | // For array of SharedFunctionInfo's (each wrapped in JSValue) | 
 | 11198 | // checks that none of them have activations on stacks (of any thread). | 
 | 11199 | // Returns array of the same length with corresponding results of | 
 | 11200 | // LiveEdit::FunctionPatchabilityStatus type. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11201 | RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11202 |   ASSERT(args.length() == 2); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11203 |   HandleScope scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11204 |   CONVERT_ARG_CHECKED(JSArray, shared_array, 0); | 
 | 11205 |   CONVERT_BOOLEAN_CHECKED(do_drop, args[1]); | 
 | 11206 |  | 
 | 11207 |   return *LiveEdit::CheckAndDropActivations(shared_array, do_drop); | 
 | 11208 | } | 
 | 11209 |  | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 11210 | // Compares 2 strings line-by-line, then token-wise and returns diff in form | 
 | 11211 | // of JSArray of triplets (pos1, pos1_end, pos2_end) describing list | 
 | 11212 | // of diff chunks. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11213 | RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11214 |   ASSERT(args.length() == 2); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11215 |   HandleScope scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11216 |   CONVERT_ARG_CHECKED(String, s1, 0); | 
 | 11217 |   CONVERT_ARG_CHECKED(String, s2, 1); | 
 | 11218 |  | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 11219 |   return *LiveEdit::CompareStrings(s1, s2); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11220 | } | 
 | 11221 |  | 
 | 11222 |  | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11223 | // A testing entry. Returns statement position which is the closest to | 
 | 11224 | // source_position. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11225 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11226 |   ASSERT(args.length() == 2); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11227 |   HandleScope scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11228 |   CONVERT_ARG_CHECKED(JSFunction, function, 0); | 
 | 11229 |   CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); | 
 | 11230 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11231 |   Handle<Code> code(function->code(), isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11232 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 11233 |   if (code->kind() != Code::FUNCTION && | 
 | 11234 |       code->kind() != Code::OPTIMIZED_FUNCTION) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11235 |     return isolate->heap()->undefined_value(); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 11236 |   } | 
 | 11237 |  | 
 | 11238 |   RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION)); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11239 |   int closest_pc = 0; | 
 | 11240 |   int distance = kMaxInt; | 
 | 11241 |   while (!it.done()) { | 
 | 11242 |     int statement_position = static_cast<int>(it.rinfo()->data()); | 
 | 11243 |     // Check if this break point is closer that what was previously found. | 
 | 11244 |     if (source_position <= statement_position && | 
 | 11245 |         statement_position - source_position < distance) { | 
 | 11246 |       closest_pc = | 
 | 11247 |           static_cast<int>(it.rinfo()->pc() - code->instruction_start()); | 
 | 11248 |       distance = statement_position - source_position; | 
 | 11249 |       // Check whether we can't get any closer. | 
 | 11250 |       if (distance == 0) break; | 
 | 11251 |     } | 
 | 11252 |     it.next(); | 
 | 11253 |   } | 
 | 11254 |  | 
 | 11255 |   return Smi::FromInt(closest_pc); | 
 | 11256 | } | 
 | 11257 |  | 
 | 11258 |  | 
 | 11259 | // Calls specified function with or without entering the debugger. | 
 | 11260 | // This is used in unit tests to run code as if debugger is entered or simply | 
 | 11261 | // to have a stack with C++ frame in the middle. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11262 | RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11263 |   ASSERT(args.length() == 2); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11264 |   HandleScope scope(isolate); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11265 |   CONVERT_ARG_CHECKED(JSFunction, function, 0); | 
 | 11266 |   CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]); | 
 | 11267 |  | 
 | 11268 |   Handle<Object> result; | 
 | 11269 |   bool pending_exception; | 
 | 11270 |   { | 
 | 11271 |     if (without_debugger) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11272 |       result = Execution::Call(function, isolate->global(), 0, NULL, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11273 |                                &pending_exception); | 
 | 11274 |     } else { | 
 | 11275 |       EnterDebugger enter_debugger; | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11276 |       result = Execution::Call(function, isolate->global(), 0, NULL, | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11277 |                                &pending_exception); | 
 | 11278 |     } | 
 | 11279 |   } | 
 | 11280 |   if (!pending_exception) { | 
 | 11281 |     return *result; | 
 | 11282 |   } else { | 
 | 11283 |     return Failure::Exception(); | 
 | 11284 |   } | 
 | 11285 | } | 
 | 11286 |  | 
 | 11287 |  | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 11288 | // Sets a v8 flag. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11289 | RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) { | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 11290 |   CONVERT_CHECKED(String, arg, args[0]); | 
 | 11291 |   SmartPointer<char> flags = | 
 | 11292 |       arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); | 
 | 11293 |   FlagList::SetFlagsFromString(*flags, StrLength(*flags)); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11294 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 11295 | } | 
 | 11296 |  | 
 | 11297 |  | 
 | 11298 | // Performs a GC. | 
 | 11299 | // Presently, it only does a full GC. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11300 | RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11301 |   isolate->heap()->CollectAllGarbage(true); | 
 | 11302 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 11303 | } | 
 | 11304 |  | 
 | 11305 |  | 
 | 11306 | // Gets the current heap usage. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11307 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11308 |   int usage = static_cast<int>(isolate->heap()->SizeOfObjects()); | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 11309 |   if (!Smi::IsValid(usage)) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11310 |     return *isolate->factory()->NewNumberFromInt(usage); | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 11311 |   } | 
 | 11312 |   return Smi::FromInt(usage); | 
 | 11313 | } | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11314 |  | 
 | 11315 |  | 
 | 11316 | // Captures a live object list from the present heap. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11317 | RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11318 | #ifdef LIVE_OBJECT_LIST | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11319 |   return isolate->heap()->true_value(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11320 | #else | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11321 |   return isolate->heap()->false_value(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11322 | #endif | 
 | 11323 | } | 
 | 11324 |  | 
 | 11325 |  | 
 | 11326 | // Captures a live object list from the present heap. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11327 | RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11328 | #ifdef LIVE_OBJECT_LIST | 
 | 11329 |   return LiveObjectList::Capture(); | 
 | 11330 | #else | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11331 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11332 | #endif | 
 | 11333 | } | 
 | 11334 |  | 
 | 11335 |  | 
 | 11336 | // Deletes the specified live object list. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11337 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11338 | #ifdef LIVE_OBJECT_LIST | 
 | 11339 |   CONVERT_SMI_CHECKED(id, args[0]); | 
 | 11340 |   bool success = LiveObjectList::Delete(id); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11341 |   return success ? isolate->heap()->true_value() : | 
 | 11342 |                    isolate->heap()->false_value(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11343 | #else | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11344 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11345 | #endif | 
 | 11346 | } | 
 | 11347 |  | 
 | 11348 |  | 
 | 11349 | // Generates the response to a debugger request for a dump of the objects | 
 | 11350 | // contained in the difference between the captured live object lists | 
 | 11351 | // specified by id1 and id2. | 
 | 11352 | // If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be | 
 | 11353 | // dumped. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11354 | RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11355 | #ifdef LIVE_OBJECT_LIST | 
 | 11356 |   HandleScope scope; | 
 | 11357 |   CONVERT_SMI_CHECKED(id1, args[0]); | 
 | 11358 |   CONVERT_SMI_CHECKED(id2, args[1]); | 
 | 11359 |   CONVERT_SMI_CHECKED(start, args[2]); | 
 | 11360 |   CONVERT_SMI_CHECKED(count, args[3]); | 
 | 11361 |   CONVERT_ARG_CHECKED(JSObject, filter_obj, 4); | 
 | 11362 |   EnterDebugger enter_debugger; | 
 | 11363 |   return LiveObjectList::Dump(id1, id2, start, count, filter_obj); | 
 | 11364 | #else | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11365 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11366 | #endif | 
 | 11367 | } | 
 | 11368 |  | 
 | 11369 |  | 
 | 11370 | // Gets the specified object as requested by the debugger. | 
 | 11371 | // This is only used for obj ids shown in live object lists. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11372 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11373 | #ifdef LIVE_OBJECT_LIST | 
 | 11374 |   CONVERT_SMI_CHECKED(obj_id, args[0]); | 
 | 11375 |   Object* result = LiveObjectList::GetObj(obj_id); | 
 | 11376 |   return result; | 
 | 11377 | #else | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11378 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11379 | #endif | 
 | 11380 | } | 
 | 11381 |  | 
 | 11382 |  | 
 | 11383 | // Gets the obj id for the specified address if valid. | 
 | 11384 | // This is only used for obj ids shown in live object lists. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11385 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11386 | #ifdef LIVE_OBJECT_LIST | 
 | 11387 |   HandleScope scope; | 
 | 11388 |   CONVERT_ARG_CHECKED(String, address, 0); | 
 | 11389 |   Object* result = LiveObjectList::GetObjId(address); | 
 | 11390 |   return result; | 
 | 11391 | #else | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11392 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11393 | #endif | 
 | 11394 | } | 
 | 11395 |  | 
 | 11396 |  | 
 | 11397 | // Gets the retainers that references the specified object alive. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11398 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11399 | #ifdef LIVE_OBJECT_LIST | 
 | 11400 |   HandleScope scope; | 
 | 11401 |   CONVERT_SMI_CHECKED(obj_id, args[0]); | 
 | 11402 |   RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject()); | 
 | 11403 |   RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean()); | 
 | 11404 |   RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi()); | 
 | 11405 |   RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi()); | 
 | 11406 |   CONVERT_ARG_CHECKED(JSObject, filter_obj, 5); | 
 | 11407 |  | 
 | 11408 |   Handle<JSObject> instance_filter; | 
 | 11409 |   if (args[1]->IsJSObject()) { | 
 | 11410 |     instance_filter = args.at<JSObject>(1); | 
 | 11411 |   } | 
 | 11412 |   bool verbose = false; | 
 | 11413 |   if (args[2]->IsBoolean()) { | 
 | 11414 |     verbose = args[2]->IsTrue(); | 
 | 11415 |   } | 
 | 11416 |   int start = 0; | 
 | 11417 |   if (args[3]->IsSmi()) { | 
 | 11418 |     start = Smi::cast(args[3])->value(); | 
 | 11419 |   } | 
 | 11420 |   int limit = Smi::kMaxValue; | 
 | 11421 |   if (args[4]->IsSmi()) { | 
 | 11422 |     limit = Smi::cast(args[4])->value(); | 
 | 11423 |   } | 
 | 11424 |  | 
 | 11425 |   return LiveObjectList::GetObjRetainers(obj_id, | 
 | 11426 |                                          instance_filter, | 
 | 11427 |                                          verbose, | 
 | 11428 |                                          start, | 
 | 11429 |                                          limit, | 
 | 11430 |                                          filter_obj); | 
 | 11431 | #else | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11432 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11433 | #endif | 
 | 11434 | } | 
 | 11435 |  | 
 | 11436 |  | 
 | 11437 | // Gets the reference path between 2 objects. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11438 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11439 | #ifdef LIVE_OBJECT_LIST | 
 | 11440 |   HandleScope scope; | 
 | 11441 |   CONVERT_SMI_CHECKED(obj_id1, args[0]); | 
 | 11442 |   CONVERT_SMI_CHECKED(obj_id2, args[1]); | 
 | 11443 |   RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject()); | 
 | 11444 |  | 
 | 11445 |   Handle<JSObject> instance_filter; | 
 | 11446 |   if (args[2]->IsJSObject()) { | 
 | 11447 |     instance_filter = args.at<JSObject>(2); | 
 | 11448 |   } | 
 | 11449 |  | 
 | 11450 |   Object* result = | 
 | 11451 |       LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter); | 
 | 11452 |   return result; | 
 | 11453 | #else | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11454 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11455 | #endif | 
 | 11456 | } | 
 | 11457 |  | 
 | 11458 |  | 
 | 11459 | // Generates the response to a debugger request for a list of all | 
 | 11460 | // previously captured live object lists. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11461 | RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11462 | #ifdef LIVE_OBJECT_LIST | 
 | 11463 |   CONVERT_SMI_CHECKED(start, args[0]); | 
 | 11464 |   CONVERT_SMI_CHECKED(count, args[1]); | 
 | 11465 |   return LiveObjectList::Info(start, count); | 
 | 11466 | #else | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11467 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11468 | #endif | 
 | 11469 | } | 
 | 11470 |  | 
 | 11471 |  | 
 | 11472 | // Gets a dump of the specified object as requested by the debugger. | 
 | 11473 | // This is only used for obj ids shown in live object lists. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11474 | RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11475 | #ifdef LIVE_OBJECT_LIST | 
 | 11476 |   HandleScope scope; | 
 | 11477 |   CONVERT_SMI_CHECKED(obj_id, args[0]); | 
 | 11478 |   Object* result = LiveObjectList::PrintObj(obj_id); | 
 | 11479 |   return result; | 
 | 11480 | #else | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11481 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11482 | #endif | 
 | 11483 | } | 
 | 11484 |  | 
 | 11485 |  | 
 | 11486 | // Resets and releases all previously captured live object lists. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11487 | RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11488 | #ifdef LIVE_OBJECT_LIST | 
 | 11489 |   LiveObjectList::Reset(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11490 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11491 | #else | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11492 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11493 | #endif | 
 | 11494 | } | 
 | 11495 |  | 
 | 11496 |  | 
 | 11497 | // Generates the response to a debugger request for a summary of the types | 
 | 11498 | // of objects in the difference between the captured live object lists | 
 | 11499 | // specified by id1 and id2. | 
 | 11500 | // If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be | 
 | 11501 | // summarized. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11502 | RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11503 | #ifdef LIVE_OBJECT_LIST | 
 | 11504 |   HandleScope scope; | 
 | 11505 |   CONVERT_SMI_CHECKED(id1, args[0]); | 
 | 11506 |   CONVERT_SMI_CHECKED(id2, args[1]); | 
 | 11507 |   CONVERT_ARG_CHECKED(JSObject, filter_obj, 2); | 
 | 11508 |  | 
 | 11509 |   EnterDebugger enter_debugger; | 
 | 11510 |   return LiveObjectList::Summarize(id1, id2, filter_obj); | 
 | 11511 | #else | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11512 |   return isolate->heap()->undefined_value(); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11513 | #endif | 
 | 11514 | } | 
 | 11515 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11516 | #endif  // ENABLE_DEBUGGER_SUPPORT | 
 | 11517 |  | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 11518 |  | 
| Ben Murdoch | 086aeea | 2011-05-13 15:57:08 +0100 | [diff] [blame] | 11519 | #ifdef ENABLE_LOGGING_AND_PROFILING | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11520 | RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) { | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 11521 |   NoHandleAllocation ha; | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 11522 |   ASSERT(args.length() == 2); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 11523 |  | 
 | 11524 |   CONVERT_CHECKED(Smi, smi_modules, args[0]); | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 11525 |   CONVERT_CHECKED(Smi, smi_tag, args[1]); | 
 | 11526 |   v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11527 |   return isolate->heap()->undefined_value(); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 11528 | } | 
 | 11529 |  | 
 | 11530 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11531 | RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) { | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 11532 |   NoHandleAllocation ha; | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 11533 |   ASSERT(args.length() == 2); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 11534 |  | 
 | 11535 |   CONVERT_CHECKED(Smi, smi_modules, args[0]); | 
| Andrei Popescu | 402d937 | 2010-02-26 13:31:12 +0000 | [diff] [blame] | 11536 |   CONVERT_CHECKED(Smi, smi_tag, args[1]); | 
 | 11537 |   v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11538 |   return isolate->heap()->undefined_value(); | 
| Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 11539 | } | 
 | 11540 |  | 
 | 11541 | #endif  // ENABLE_LOGGING_AND_PROFILING | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11542 |  | 
 | 11543 | // Finds the script object from the script data. NOTE: This operation uses | 
 | 11544 | // heap traversal to find the function generated for the source position | 
 | 11545 | // for the requested break point. For lazily compiled functions several heap | 
 | 11546 | // traversals might be required rendering this operation as a rather slow | 
 | 11547 | // operation. However for setting break points which is normally done through | 
 | 11548 | // some kind of user interaction the performance is not crucial. | 
 | 11549 | static Handle<Object> Runtime_GetScriptFromScriptName( | 
 | 11550 |     Handle<String> script_name) { | 
 | 11551 |   // Scan the heap for Script objects to find the script with the requested | 
 | 11552 |   // script data. | 
 | 11553 |   Handle<Script> script; | 
 | 11554 |   HeapIterator iterator; | 
| Leon Clarke | d91b9f7 | 2010-01-27 17:25:45 +0000 | [diff] [blame] | 11555 |   HeapObject* obj = NULL; | 
 | 11556 |   while (script.is_null() && ((obj = iterator.next()) != NULL)) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11557 |     // If a script is found check if it has the script data requested. | 
 | 11558 |     if (obj->IsScript()) { | 
 | 11559 |       if (Script::cast(obj)->name()->IsString()) { | 
 | 11560 |         if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) { | 
 | 11561 |           script = Handle<Script>(Script::cast(obj)); | 
 | 11562 |         } | 
 | 11563 |       } | 
 | 11564 |     } | 
 | 11565 |   } | 
 | 11566 |  | 
 | 11567 |   // If no script with the requested script data is found return undefined. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11568 |   if (script.is_null()) return FACTORY->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11569 |  | 
 | 11570 |   // Return the script found. | 
 | 11571 |   return GetScriptWrapper(script); | 
 | 11572 | } | 
 | 11573 |  | 
 | 11574 |  | 
 | 11575 | // Get the script object from script data. NOTE: Regarding performance | 
 | 11576 | // see the NOTE for GetScriptFromScriptData. | 
 | 11577 | // args[0]: script data for the script to find the source for | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11578 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11579 |   HandleScope scope(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11580 |  | 
 | 11581 |   ASSERT(args.length() == 1); | 
 | 11582 |  | 
 | 11583 |   CONVERT_CHECKED(String, script_name, args[0]); | 
 | 11584 |  | 
 | 11585 |   // Find the requested script. | 
 | 11586 |   Handle<Object> result = | 
 | 11587 |       Runtime_GetScriptFromScriptName(Handle<String>(script_name)); | 
 | 11588 |   return *result; | 
 | 11589 | } | 
 | 11590 |  | 
 | 11591 |  | 
 | 11592 | // Determines whether the given stack frame should be displayed in | 
 | 11593 | // a stack trace.  The caller is the error constructor that asked | 
 | 11594 | // for the stack trace to be collected.  The first time a construct | 
 | 11595 | // call to this function is encountered it is skipped.  The seen_caller | 
 | 11596 | // in/out parameter is used to remember if the caller has been seen | 
 | 11597 | // yet. | 
 | 11598 | static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller, | 
 | 11599 |     bool* seen_caller) { | 
 | 11600 |   // Only display JS frames. | 
 | 11601 |   if (!raw_frame->is_java_script()) | 
 | 11602 |     return false; | 
 | 11603 |   JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); | 
 | 11604 |   Object* raw_fun = frame->function(); | 
 | 11605 |   // Not sure when this can happen but skip it just in case. | 
 | 11606 |   if (!raw_fun->IsJSFunction()) | 
 | 11607 |     return false; | 
 | 11608 |   if ((raw_fun == caller) && !(*seen_caller)) { | 
 | 11609 |     *seen_caller = true; | 
 | 11610 |     return false; | 
 | 11611 |   } | 
 | 11612 |   // Skip all frames until we've seen the caller.  Also, skip the most | 
 | 11613 |   // obvious builtin calls.  Some builtin calls (such as Number.ADD | 
 | 11614 |   // which is invoked using 'call') are very difficult to recognize | 
 | 11615 |   // so we're leaving them in for now. | 
 | 11616 |   return *seen_caller && !frame->receiver()->IsJSBuiltinsObject(); | 
 | 11617 | } | 
 | 11618 |  | 
 | 11619 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 11620 | // Collect the raw data for a stack trace.  Returns an array of 4 | 
 | 11621 | // element segments each containing a receiver, function, code and | 
 | 11622 | // native code offset. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11623 | RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11624 |   ASSERT_EQ(args.length(), 2); | 
 | 11625 |   Handle<Object> caller = args.at<Object>(0); | 
 | 11626 |   CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]); | 
 | 11627 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11628 |   HandleScope scope(isolate); | 
 | 11629 |   Factory* factory = isolate->factory(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11630 |  | 
| Leon Clarke | e46be81 | 2010-01-19 14:06:41 +0000 | [diff] [blame] | 11631 |   limit = Max(limit, 0);  // Ensure that limit is not negative. | 
 | 11632 |   int initial_size = Min(limit, 10); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11633 |   Handle<FixedArray> elements = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11634 |       factory->NewFixedArrayWithHoles(initial_size * 4); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11635 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11636 |   StackFrameIterator iter(isolate); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11637 |   // If the caller parameter is a function we skip frames until we're | 
 | 11638 |   // under it before starting to collect. | 
 | 11639 |   bool seen_caller = !caller->IsJSFunction(); | 
 | 11640 |   int cursor = 0; | 
 | 11641 |   int frames_seen = 0; | 
 | 11642 |   while (!iter.done() && frames_seen < limit) { | 
 | 11643 |     StackFrame* raw_frame = iter.frame(); | 
 | 11644 |     if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) { | 
 | 11645 |       frames_seen++; | 
 | 11646 |       JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11647 |       // Set initial size to the maximum inlining level + 1 for the outermost | 
 | 11648 |       // function. | 
 | 11649 |       List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1); | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 11650 |       frame->Summarize(&frames); | 
 | 11651 |       for (int i = frames.length() - 1; i >= 0; i--) { | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11652 |         if (cursor + 4 > elements->length()) { | 
 | 11653 |           int new_capacity = JSObject::NewElementsCapacity(elements->length()); | 
 | 11654 |           Handle<FixedArray> new_elements = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11655 |               factory->NewFixedArrayWithHoles(new_capacity); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11656 |           for (int i = 0; i < cursor; i++) { | 
 | 11657 |             new_elements->set(i, elements->get(i)); | 
 | 11658 |           } | 
 | 11659 |           elements = new_elements; | 
 | 11660 |         } | 
 | 11661 |         ASSERT(cursor + 4 <= elements->length()); | 
 | 11662 |  | 
| Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 11663 |         Handle<Object> recv = frames[i].receiver(); | 
 | 11664 |         Handle<JSFunction> fun = frames[i].function(); | 
 | 11665 |         Handle<Code> code = frames[i].code(); | 
 | 11666 |         Handle<Smi> offset(Smi::FromInt(frames[i].offset())); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11667 |         elements->set(cursor++, *recv); | 
 | 11668 |         elements->set(cursor++, *fun); | 
 | 11669 |         elements->set(cursor++, *code); | 
 | 11670 |         elements->set(cursor++, *offset); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11671 |       } | 
 | 11672 |     } | 
 | 11673 |     iter.Advance(); | 
 | 11674 |   } | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11675 |   Handle<JSArray> result = factory->NewJSArrayWithElements(elements); | 
| Leon Clarke | 4515c47 | 2010-02-03 11:58:03 +0000 | [diff] [blame] | 11676 |   result->set_length(Smi::FromInt(cursor)); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11677 |   return *result; | 
 | 11678 | } | 
 | 11679 |  | 
 | 11680 |  | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 11681 | // Returns V8 version as a string. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11682 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) { | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 11683 |   ASSERT_EQ(args.length(), 0); | 
 | 11684 |  | 
 | 11685 |   NoHandleAllocation ha; | 
 | 11686 |  | 
 | 11687 |   const char* version_string = v8::V8::GetVersion(); | 
 | 11688 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11689 |   return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string), | 
 | 11690 |                                                   NOT_TENURED); | 
| Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 11691 | } | 
 | 11692 |  | 
 | 11693 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11694 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11695 |   ASSERT(args.length() == 2); | 
 | 11696 |   OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) + | 
 | 11697 |                                     Smi::cast(args[1])->value()); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11698 |   isolate->PrintStack(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11699 |   OS::Abort(); | 
 | 11700 |   UNREACHABLE(); | 
 | 11701 |   return NULL; | 
 | 11702 | } | 
 | 11703 |  | 
 | 11704 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11705 | RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) { | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11706 |   // This is only called from codegen, so checks might be more lax. | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 11707 |   CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11708 |   Object* key = args[1]; | 
 | 11709 |  | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 11710 |   int finger_index = cache->finger_index(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11711 |   Object* o = cache->get(finger_index); | 
 | 11712 |   if (o == key) { | 
 | 11713 |     // The fastest case: hit the same place again. | 
 | 11714 |     return cache->get(finger_index + 1); | 
 | 11715 |   } | 
 | 11716 |  | 
 | 11717 |   for (int i = finger_index - 2; | 
 | 11718 |        i >= JSFunctionResultCache::kEntriesIndex; | 
 | 11719 |        i -= 2) { | 
 | 11720 |     o = cache->get(i); | 
 | 11721 |     if (o == key) { | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 11722 |       cache->set_finger_index(i); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11723 |       return cache->get(i + 1); | 
 | 11724 |     } | 
 | 11725 |   } | 
 | 11726 |  | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 11727 |   int size = cache->size(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11728 |   ASSERT(size <= cache->length()); | 
 | 11729 |  | 
 | 11730 |   for (int i = size - 2; i > finger_index; i -= 2) { | 
 | 11731 |     o = cache->get(i); | 
 | 11732 |     if (o == key) { | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 11733 |       cache->set_finger_index(i); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11734 |       return cache->get(i + 1); | 
 | 11735 |     } | 
 | 11736 |   } | 
 | 11737 |  | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 11738 |   // There is no value in the cache.  Invoke the function and cache result. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11739 |   HandleScope scope(isolate); | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 11740 |  | 
 | 11741 |   Handle<JSFunctionResultCache> cache_handle(cache); | 
 | 11742 |   Handle<Object> key_handle(key); | 
 | 11743 |   Handle<Object> value; | 
 | 11744 |   { | 
 | 11745 |     Handle<JSFunction> factory(JSFunction::cast( | 
 | 11746 |           cache_handle->get(JSFunctionResultCache::kFactoryIndex))); | 
 | 11747 |     // TODO(antonm): consider passing a receiver when constructing a cache. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11748 |     Handle<Object> receiver(isolate->global_context()->global()); | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 11749 |     // This handle is nor shared, nor used later, so it's safe. | 
 | 11750 |     Object** argv[] = { key_handle.location() }; | 
 | 11751 |     bool pending_exception = false; | 
 | 11752 |     value = Execution::Call(factory, | 
 | 11753 |                             receiver, | 
 | 11754 |                             1, | 
 | 11755 |                             argv, | 
 | 11756 |                             &pending_exception); | 
 | 11757 |     if (pending_exception) return Failure::Exception(); | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11758 |   } | 
| Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 11759 |  | 
 | 11760 | #ifdef DEBUG | 
 | 11761 |   cache_handle->JSFunctionResultCacheVerify(); | 
 | 11762 | #endif | 
 | 11763 |  | 
 | 11764 |   // Function invocation may have cleared the cache.  Reread all the data. | 
 | 11765 |   finger_index = cache_handle->finger_index(); | 
 | 11766 |   size = cache_handle->size(); | 
 | 11767 |  | 
 | 11768 |   // If we have spare room, put new data into it, otherwise evict post finger | 
 | 11769 |   // entry which is likely to be the least recently used. | 
 | 11770 |   int index = -1; | 
 | 11771 |   if (size < cache_handle->length()) { | 
 | 11772 |     cache_handle->set_size(size + JSFunctionResultCache::kEntrySize); | 
 | 11773 |     index = size; | 
 | 11774 |   } else { | 
 | 11775 |     index = finger_index + JSFunctionResultCache::kEntrySize; | 
 | 11776 |     if (index == cache_handle->length()) { | 
 | 11777 |       index = JSFunctionResultCache::kEntriesIndex; | 
 | 11778 |     } | 
 | 11779 |   } | 
 | 11780 |  | 
 | 11781 |   ASSERT(index % 2 == 0); | 
 | 11782 |   ASSERT(index >= JSFunctionResultCache::kEntriesIndex); | 
 | 11783 |   ASSERT(index < cache_handle->length()); | 
 | 11784 |  | 
 | 11785 |   cache_handle->set(index, *key_handle); | 
 | 11786 |   cache_handle->set(index + 1, *value); | 
 | 11787 |   cache_handle->set_finger_index(index); | 
 | 11788 |  | 
 | 11789 | #ifdef DEBUG | 
 | 11790 |   cache_handle->JSFunctionResultCacheVerify(); | 
 | 11791 | #endif | 
 | 11792 |  | 
 | 11793 |   return *value; | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11794 | } | 
 | 11795 |  | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 11796 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11797 | RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11798 |   HandleScope scope(isolate); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 11799 |   CONVERT_ARG_CHECKED(String, type, 0); | 
 | 11800 |   CONVERT_ARG_CHECKED(JSArray, arguments, 1); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11801 |   return *isolate->factory()->NewJSMessageObject( | 
 | 11802 |       type, | 
 | 11803 |       arguments, | 
 | 11804 |       0, | 
 | 11805 |       0, | 
 | 11806 |       isolate->factory()->undefined_value(), | 
 | 11807 |       isolate->factory()->undefined_value(), | 
 | 11808 |       isolate->factory()->undefined_value()); | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 11809 | } | 
 | 11810 |  | 
 | 11811 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11812 | RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) { | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 11813 |   CONVERT_CHECKED(JSMessageObject, message, args[0]); | 
 | 11814 |   return message->type(); | 
 | 11815 | } | 
 | 11816 |  | 
 | 11817 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11818 | RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) { | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 11819 |   CONVERT_CHECKED(JSMessageObject, message, args[0]); | 
 | 11820 |   return message->arguments(); | 
 | 11821 | } | 
 | 11822 |  | 
 | 11823 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11824 | RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) { | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 11825 |   CONVERT_CHECKED(JSMessageObject, message, args[0]); | 
 | 11826 |   return Smi::FromInt(message->start_position()); | 
 | 11827 | } | 
 | 11828 |  | 
 | 11829 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11830 | RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) { | 
| Steve Block | 1e0659c | 2011-05-24 12:43:12 +0100 | [diff] [blame] | 11831 |   CONVERT_CHECKED(JSMessageObject, message, args[0]); | 
 | 11832 |   return message->script(); | 
 | 11833 | } | 
 | 11834 |  | 
 | 11835 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11836 | #ifdef DEBUG | 
 | 11837 | // ListNatives is ONLY used by the fuzz-natives.js in debug mode | 
 | 11838 | // Exclude the code in release mode. | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11839 | RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11840 |   ASSERT(args.length() == 0); | 
 | 11841 |   HandleScope scope; | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11842 | #define COUNT_ENTRY(Name, argc, ressize) + 1 | 
 | 11843 |   int entry_count = 0 | 
 | 11844 |       RUNTIME_FUNCTION_LIST(COUNT_ENTRY) | 
 | 11845 |       INLINE_FUNCTION_LIST(COUNT_ENTRY) | 
 | 11846 |       INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY); | 
 | 11847 | #undef COUNT_ENTRY | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11848 |   Factory* factory = isolate->factory(); | 
 | 11849 |   Handle<FixedArray> elements = factory->NewFixedArray(entry_count); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11850 |   int index = 0; | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11851 |   bool inline_runtime_functions = false; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11852 | #define ADD_ENTRY(Name, argc, ressize)                                       \ | 
 | 11853 |   {                                                                          \ | 
 | 11854 |     HandleScope inner;                                                       \ | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11855 |     Handle<String> name;                                                     \ | 
 | 11856 |     /* Inline runtime functions have an underscore in front of the name. */  \ | 
 | 11857 |     if (inline_runtime_functions) {                                          \ | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11858 |       name = factory->NewStringFromAscii(                                    \ | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11859 |           Vector<const char>("_" #Name, StrLength("_" #Name)));              \ | 
 | 11860 |     } else {                                                                 \ | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11861 |       name = factory->NewStringFromAscii(                                    \ | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11862 |           Vector<const char>(#Name, StrLength(#Name)));                      \ | 
 | 11863 |     }                                                                        \ | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11864 |     Handle<FixedArray> pair_elements = factory->NewFixedArray(2);            \ | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11865 |     pair_elements->set(0, *name);                                            \ | 
 | 11866 |     pair_elements->set(1, Smi::FromInt(argc));                               \ | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11867 |     Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements);   \ | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11868 |     elements->set(index++, *pair);                                           \ | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11869 |   } | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11870 |   inline_runtime_functions = false; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11871 |   RUNTIME_FUNCTION_LIST(ADD_ENTRY) | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11872 |   inline_runtime_functions = true; | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 11873 |   INLINE_FUNCTION_LIST(ADD_ENTRY) | 
| Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 11874 |   INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY) | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11875 | #undef ADD_ENTRY | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 11876 |   ASSERT_EQ(index, entry_count); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11877 |   Handle<JSArray> result = factory->NewJSArrayWithElements(elements); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11878 |   return *result; | 
 | 11879 | } | 
 | 11880 | #endif | 
 | 11881 |  | 
 | 11882 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11883 | RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11884 |   ASSERT(args.length() == 2); | 
 | 11885 |   CONVERT_CHECKED(String, format, args[0]); | 
 | 11886 |   CONVERT_CHECKED(JSArray, elms, args[1]); | 
 | 11887 |   Vector<const char> chars = format->ToAsciiVector(); | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11888 |   LOGGER->LogRuntime(chars, elms); | 
 | 11889 |   return isolate->heap()->undefined_value(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11890 | } | 
 | 11891 |  | 
 | 11892 |  | 
| Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 11893 | RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11894 |   UNREACHABLE();  // implemented as macro in the parser | 
 | 11895 |   return NULL; | 
 | 11896 | } | 
 | 11897 |  | 
 | 11898 |  | 
 | 11899 | // ---------------------------------------------------------------------------- | 
 | 11900 | // Implementation of Runtime | 
 | 11901 |  | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 11902 | #define F(name, number_of_args, result_size)                             \ | 
 | 11903 |   { Runtime::k##name, Runtime::RUNTIME, #name,   \ | 
 | 11904 |     FUNCTION_ADDR(Runtime_##name), number_of_args, result_size }, | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11905 |  | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 11906 |  | 
 | 11907 | #define I(name, number_of_args, result_size)                             \ | 
 | 11908 |   { Runtime::kInline##name, Runtime::INLINE,     \ | 
 | 11909 |     "_" #name, NULL, number_of_args, result_size }, | 
 | 11910 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11911 | static const Runtime::Function kIntrinsicFunctions[] = { | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11912 |   RUNTIME_FUNCTION_LIST(F) | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 11913 |   INLINE_FUNCTION_LIST(I) | 
 | 11914 |   INLINE_RUNTIME_FUNCTION_LIST(I) | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11915 | }; | 
 | 11916 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11917 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11918 | MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap, | 
 | 11919 |                                                        Object* dictionary) { | 
 | 11920 |   ASSERT(Isolate::Current()->heap() == heap); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 11921 |   ASSERT(dictionary != NULL); | 
 | 11922 |   ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0); | 
 | 11923 |   for (int i = 0; i < kNumFunctions; ++i) { | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 11924 |     Object* name_symbol; | 
 | 11925 |     { MaybeObject* maybe_name_symbol = | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11926 |           heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 11927 |       if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol; | 
 | 11928 |     } | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 11929 |     StringDictionary* string_dictionary = StringDictionary::cast(dictionary); | 
| John Reck | 5913587 | 2010-11-02 12:39:01 -0700 | [diff] [blame] | 11930 |     { MaybeObject* maybe_dictionary = string_dictionary->Add( | 
 | 11931 |           String::cast(name_symbol), | 
 | 11932 |           Smi::FromInt(i), | 
 | 11933 |           PropertyDetails(NONE, NORMAL)); | 
 | 11934 |       if (!maybe_dictionary->ToObject(&dictionary)) { | 
 | 11935 |         // Non-recoverable failure.  Calling code must restart heap | 
 | 11936 |         // initialization. | 
 | 11937 |         return maybe_dictionary; | 
 | 11938 |       } | 
 | 11939 |     } | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 11940 |   } | 
 | 11941 |   return dictionary; | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11942 | } | 
 | 11943 |  | 
 | 11944 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11945 | const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) { | 
 | 11946 |   Heap* heap = name->GetHeap(); | 
 | 11947 |   int entry = heap->intrinsic_function_names()->FindEntry(*name); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 11948 |   if (entry != kNotFound) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11949 |     Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry); | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 11950 |     int function_index = Smi::cast(smi_index)->value(); | 
 | 11951 |     return &(kIntrinsicFunctions[function_index]); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11952 |   } | 
 | 11953 |   return NULL; | 
 | 11954 | } | 
 | 11955 |  | 
 | 11956 |  | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11957 | const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) { | 
| Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 11958 |   return &(kIntrinsicFunctions[static_cast<int>(id)]); | 
 | 11959 | } | 
 | 11960 |  | 
 | 11961 |  | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11962 | void Runtime::PerformGC(Object* result) { | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11963 |   Isolate* isolate = Isolate::Current(); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11964 |   Failure* failure = Failure::cast(result); | 
 | 11965 |   if (failure->IsRetryAfterGC()) { | 
 | 11966 |     // Try to do a garbage collection; ignore it if it fails. The C | 
 | 11967 |     // entry stub will throw an out-of-memory exception in that case. | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11968 |     isolate->heap()->CollectGarbage(failure->allocation_space()); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11969 |   } else { | 
 | 11970 |     // Handle last resort GC and make sure to allow future allocations | 
 | 11971 |     // to grow the heap without causing GCs (if possible). | 
| Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 11972 |     isolate->counters()->gc_last_resort_from_js()->Increment(); | 
 | 11973 |     isolate->heap()->CollectAllGarbage(false); | 
| Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 11974 |   } | 
 | 11975 | } | 
 | 11976 |  | 
 | 11977 |  | 
 | 11978 | } }  // namespace v8::internal |