blob: 2aa443122c9713e5f11ba00e0b540bd3b3c26445 [file] [log] [blame]
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001// Copyright 2010 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
43#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000044#include "liveedit.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000045#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "platform.h"
47#include "runtime.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000048#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000050#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000051#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000052#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000053#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054
kasperl@chromium.org71affb52009-05-26 05:44:31 +000055namespace v8 {
56namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
58
ager@chromium.org3e875802009-06-29 08:26:34 +000059#define RUNTIME_ASSERT(value) \
60 if (!(value)) return Top::ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
62// Cast the given object to a value of the specified type and store
63// it in a variable with the given name. If the object is not of the
64// expected type call IllegalOperation and return.
65#define CONVERT_CHECKED(Type, name, obj) \
66 RUNTIME_ASSERT(obj->Is##Type()); \
67 Type* name = Type::cast(obj);
68
69#define CONVERT_ARG_CHECKED(Type, name, index) \
70 RUNTIME_ASSERT(args[index]->Is##Type()); \
71 Handle<Type> name = args.at<Type>(index);
72
kasper.lundbd3ec4e2008-07-09 11:06:54 +000073// Cast the given object to a boolean and store it in a variable with
74// the given name. If the object is not a boolean call IllegalOperation
75// and return.
76#define CONVERT_BOOLEAN_CHECKED(name, obj) \
77 RUNTIME_ASSERT(obj->IsBoolean()); \
78 bool name = (obj)->IsTrue();
79
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000080// Cast the given object to a Smi and store its value in an int variable
81// with the given name. If the object is not a Smi call IllegalOperation
82// and return.
83#define CONVERT_SMI_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsSmi()); \
85 int name = Smi::cast(obj)->value();
86
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087// Cast the given object to a double and store it in a variable with
88// the given name. If the object is not a number (as opposed to
89// the number not-a-number) call IllegalOperation and return.
90#define CONVERT_DOUBLE_CHECKED(name, obj) \
91 RUNTIME_ASSERT(obj->IsNumber()); \
92 double name = (obj)->Number();
93
94// Call the specified converter on the object *comand store the result in
95// a variable of the specified type with the given name. If the
96// object is not a Number call IllegalOperation and return.
97#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
98 RUNTIME_ASSERT(obj->IsNumber()); \
99 type name = NumberTo##Type(obj);
100
101// Non-reentrant string buffer for efficient general use in this file.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000102static StaticResource<StringInputBuffer> runtime_string_input_buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
104
lrn@chromium.org303ada72010-10-27 09:33:13 +0000105MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000106 StackLimitCheck check;
107 if (check.HasOverflowed()) return Top::StackOverflow();
108
lrn@chromium.org303ada72010-10-27 09:33:13 +0000109 Object* result;
110 { MaybeObject* maybe_result = Heap::CopyJSObject(boilerplate);
111 if (!maybe_result->ToObject(&result)) return maybe_result;
112 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000113 JSObject* copy = JSObject::cast(result);
114
115 // Deep copy local properties.
116 if (copy->HasFastProperties()) {
117 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 for (int i = 0; i < properties->length(); i++) {
119 Object* value = properties->get(i);
120 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000121 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000122 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
123 if (!maybe_result->ToObject(&result)) return maybe_result;
124 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000126 }
127 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000128 int nof = copy->map()->inobject_properties();
129 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130 Object* value = copy->InObjectPropertyAt(i);
131 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000132 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000133 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
134 if (!maybe_result->ToObject(&result)) return maybe_result;
135 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000136 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000137 }
138 }
139 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000140 { MaybeObject* maybe_result =
141 Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
142 if (!maybe_result->ToObject(&result)) return maybe_result;
143 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000144 FixedArray* names = FixedArray::cast(result);
145 copy->GetLocalPropertyNames(names, 0);
146 for (int i = 0; i < names->length(); i++) {
147 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000150 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 // Only deep copy fields from the object literal expression.
152 // In particular, don't try to copy the length attribute of
153 // an array.
154 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000155 Object* value =
156 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000158 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
160 if (!maybe_result->ToObject(&result)) return maybe_result;
161 }
162 { MaybeObject* maybe_result =
163 copy->SetProperty(key_string, result, NONE);
164 if (!maybe_result->ToObject(&result)) return maybe_result;
165 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000166 }
167 }
168 }
169
170 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000171 // Pixel elements cannot be created using an object literal.
ager@chromium.org3811b432009-10-28 14:53:37 +0000172 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000173 switch (copy->GetElementsKind()) {
174 case JSObject::FAST_ELEMENTS: {
175 FixedArray* elements = FixedArray::cast(copy->elements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000176 if (elements->map() == Heap::fixed_cow_array_map()) {
177 Counters::cow_arrays_created_runtime.Increment();
178#ifdef DEBUG
179 for (int i = 0; i < elements->length(); i++) {
180 ASSERT(!elements->get(i)->IsJSObject());
181 }
182#endif
183 } else {
184 for (int i = 0; i < elements->length(); i++) {
185 Object* value = elements->get(i);
186 if (value->IsJSObject()) {
187 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000188 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
189 if (!maybe_result->ToObject(&result)) return maybe_result;
190 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000191 elements->set(i, result);
192 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 }
194 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000195 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000197 case JSObject::DICTIONARY_ELEMENTS: {
198 NumberDictionary* element_dictionary = copy->element_dictionary();
199 int capacity = element_dictionary->Capacity();
200 for (int i = 0; i < capacity; i++) {
201 Object* k = element_dictionary->KeyAt(i);
202 if (element_dictionary->IsKey(k)) {
203 Object* value = element_dictionary->ValueAt(i);
204 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000205 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000206 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
207 if (!maybe_result->ToObject(&result)) return maybe_result;
208 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000209 element_dictionary->ValueAtPut(i, result);
210 }
211 }
212 }
213 break;
214 }
215 default:
216 UNREACHABLE();
217 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000218 }
219 return copy;
220}
221
222
lrn@chromium.org303ada72010-10-27 09:33:13 +0000223static MaybeObject* Runtime_CloneLiteralBoilerplate(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000224 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
225 return DeepCopyBoilerplate(boilerplate);
226}
227
228
lrn@chromium.org303ada72010-10-27 09:33:13 +0000229static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000231 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000232}
233
234
ager@chromium.org236ad962008-09-25 09:45:57 +0000235static Handle<Map> ComputeObjectLiteralMap(
236 Handle<Context> context,
237 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000238 bool* is_result_from_cache) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000239 int properties_length = constant_properties->length();
240 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000241 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000242 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000243 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000244 for (int p = 0; p != properties_length; p += 2) {
245 Object* key = constant_properties->get(p);
246 uint32_t element_index = 0;
247 if (key->IsSymbol()) {
248 number_of_symbol_keys++;
249 } else if (key->ToArrayIndex(&element_index)) {
250 // An index key does not require space in the property backing store.
251 number_of_properties--;
252 } else {
253 // Bail out as a non-symbol non-index key makes caching impossible.
254 // ASSERT to make sure that the if condition after the loop is false.
255 ASSERT(number_of_symbol_keys != number_of_properties);
256 break;
257 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000258 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000259 // If we only have symbols and array indices among keys then we can
260 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000262 if ((number_of_symbol_keys == number_of_properties) &&
263 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 // Create the fixed array with the key.
265 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000266 if (number_of_symbol_keys > 0) {
267 int index = 0;
268 for (int p = 0; p < properties_length; p += 2) {
269 Object* key = constant_properties->get(p);
270 if (key->IsSymbol()) {
271 keys->set(index++, key);
272 }
273 }
274 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000275 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000276 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000277 return Factory::ObjectLiteralMapFromCache(context, keys);
278 }
279 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000280 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000281 return Factory::CopyMap(
282 Handle<Map>(context->object_function()->initial_map()),
283 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284}
285
286
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000287static Handle<Object> CreateLiteralBoilerplate(
288 Handle<FixedArray> literals,
289 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000290
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000291
292static Handle<Object> CreateObjectLiteralBoilerplate(
293 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000294 Handle<FixedArray> constant_properties,
295 bool should_have_fast_elements) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000296 // Get the global context from the literals array. This is the
297 // context in which the function was created and we use the object
298 // function from this context to create the object literal. We do
299 // not use the object function from the current global context
300 // because this might be the object function from another context
301 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000302 Handle<Context> context =
303 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
304
305 bool is_result_from_cache;
306 Handle<Map> map = ComputeObjectLiteralMap(context,
307 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000308 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309
ager@chromium.org236ad962008-09-25 09:45:57 +0000310 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000311
312 // Normalize the elements of the boilerplate to save space if needed.
313 if (!should_have_fast_elements) NormalizeElements(boilerplate);
314
ager@chromium.org32912102009-01-16 10:38:43 +0000315 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000316 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000317 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000318 length / 2,
ager@chromium.org236ad962008-09-25 09:45:57 +0000319 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320 for (int index = 0; index < length; index +=2) {
321 Handle<Object> key(constant_properties->get(index+0));
322 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000323 if (value->IsFixedArray()) {
324 // The value contains the constant_properties of a
325 // simple object literal.
326 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
327 value = CreateLiteralBoilerplate(literals, array);
328 if (value.is_null()) return value;
329 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000330 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000331 uint32_t element_index = 0;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000332 if (key->IsSymbol()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000333 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
334 // Array index as string (uint32).
335 result = SetOwnElement(boilerplate, element_index, value);
336 } else {
337 Handle<String> name(String::cast(*key));
338 ASSERT(!name->AsArrayIndex(&element_index));
339 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
340 value, NONE);
341 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000342 } else if (key->ToArrayIndex(&element_index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 // Array index (uint32).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000344 result = SetOwnElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345 } else {
346 // Non-uint32 number.
347 ASSERT(key->IsNumber());
348 double num = key->Number();
349 char arr[100];
350 Vector<char> buffer(arr, ARRAY_SIZE(arr));
351 const char* str = DoubleToCString(num, buffer);
352 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000353 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
354 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000356 // If setting the property on the boilerplate throws an
357 // exception, the exception is converted to an empty handle in
358 // the handle based operations. In that case, we need to
359 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000360 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 }
362 }
363
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000364 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000365}
366
367
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000368static Handle<Object> CreateArrayLiteralBoilerplate(
369 Handle<FixedArray> literals,
370 Handle<FixedArray> elements) {
371 // Create the JSArray.
372 Handle<JSFunction> constructor(
373 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
374 Handle<Object> object = Factory::NewJSObject(constructor);
375
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000376 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
377 Handle<FixedArray> copied_elements =
378 is_cow ? elements : Factory::CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000379
380 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000381 if (is_cow) {
382#ifdef DEBUG
383 // Copy-on-write arrays must be shallow (and simple).
384 for (int i = 0; i < content->length(); i++) {
385 ASSERT(!content->get(i)->IsFixedArray());
386 }
387#endif
388 } else {
389 for (int i = 0; i < content->length(); i++) {
390 if (content->get(i)->IsFixedArray()) {
391 // The value contains the constant_properties of a
392 // simple object literal.
393 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
394 Handle<Object> result =
395 CreateLiteralBoilerplate(literals, fa);
396 if (result.is_null()) return result;
397 content->set(i, *result);
398 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000399 }
400 }
401
402 // Set the elements.
403 Handle<JSArray>::cast(object)->SetContent(*content);
404 return object;
405}
406
407
408static Handle<Object> CreateLiteralBoilerplate(
409 Handle<FixedArray> literals,
410 Handle<FixedArray> array) {
411 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
412 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000413 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
414 return CreateObjectLiteralBoilerplate(literals, elements, true);
415 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
416 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000417 case CompileTimeValue::ARRAY_LITERAL:
418 return CreateArrayLiteralBoilerplate(literals, elements);
419 default:
420 UNREACHABLE();
421 return Handle<Object>::null();
422 }
423}
424
425
lrn@chromium.org303ada72010-10-27 09:33:13 +0000426static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000427 // Takes a FixedArray of elements containing the literal elements of
428 // the array literal and produces JSArray with those elements.
429 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000430 // which contains the context from which to get the Array function
431 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000432 HandleScope scope;
433 ASSERT(args.length() == 3);
434 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
435 CONVERT_SMI_CHECKED(literals_index, args[1]);
436 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
439 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000441 // Update the functions literal and return the boilerplate.
442 literals->set(literals_index, *object);
443 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444}
445
446
lrn@chromium.org303ada72010-10-27 09:33:13 +0000447static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000448 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000449 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000450 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
451 CONVERT_SMI_CHECKED(literals_index, args[1]);
452 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000453 CONVERT_SMI_CHECKED(fast_elements, args[3]);
454 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000455
456 // Check if boilerplate exists. If not, create it first.
457 Handle<Object> boilerplate(literals->get(literals_index));
458 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000459 boilerplate = CreateObjectLiteralBoilerplate(literals,
460 constant_properties,
461 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000462 if (boilerplate.is_null()) return Failure::Exception();
463 // Update the functions literal and return the boilerplate.
464 literals->set(literals_index, *boilerplate);
465 }
466 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
467}
468
469
lrn@chromium.org303ada72010-10-27 09:33:13 +0000470static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000471 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000472 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000473 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
474 CONVERT_SMI_CHECKED(literals_index, args[1]);
475 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000476 CONVERT_SMI_CHECKED(fast_elements, args[3]);
477 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000478
479 // Check if boilerplate exists. If not, create it first.
480 Handle<Object> boilerplate(literals->get(literals_index));
481 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000482 boilerplate = CreateObjectLiteralBoilerplate(literals,
483 constant_properties,
484 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000485 if (boilerplate.is_null()) return Failure::Exception();
486 // Update the functions literal and return the boilerplate.
487 literals->set(literals_index, *boilerplate);
488 }
489 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
490}
491
492
lrn@chromium.org303ada72010-10-27 09:33:13 +0000493static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000494 HandleScope scope;
495 ASSERT(args.length() == 3);
496 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
497 CONVERT_SMI_CHECKED(literals_index, args[1]);
498 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
499
500 // Check if boilerplate exists. If not, create it first.
501 Handle<Object> boilerplate(literals->get(literals_index));
502 if (*boilerplate == Heap::undefined_value()) {
503 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
504 if (boilerplate.is_null()) return Failure::Exception();
505 // Update the functions literal and return the boilerplate.
506 literals->set(literals_index, *boilerplate);
507 }
508 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
509}
510
511
lrn@chromium.org303ada72010-10-27 09:33:13 +0000512static MaybeObject* Runtime_CreateArrayLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000513 HandleScope scope;
514 ASSERT(args.length() == 3);
515 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
516 CONVERT_SMI_CHECKED(literals_index, args[1]);
517 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
518
519 // Check if boilerplate exists. If not, create it first.
520 Handle<Object> boilerplate(literals->get(literals_index));
521 if (*boilerplate == Heap::undefined_value()) {
522 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
523 if (boilerplate.is_null()) return Failure::Exception();
524 // Update the functions literal and return the boilerplate.
525 literals->set(literals_index, *boilerplate);
526 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000527 if (JSObject::cast(*boilerplate)->elements()->map() ==
528 Heap::fixed_cow_array_map()) {
529 Counters::cow_arrays_created_runtime.Increment();
530 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000531 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
532}
533
534
lrn@chromium.org303ada72010-10-27 09:33:13 +0000535static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
ager@chromium.org32912102009-01-16 10:38:43 +0000536 ASSERT(args.length() == 2);
537 CONVERT_CHECKED(String, key, args[0]);
538 Object* value = args[1];
539 // Create a catch context extension object.
540 JSFunction* constructor =
541 Top::context()->global_context()->context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000542 Object* object;
543 { MaybeObject* maybe_object = Heap::AllocateJSObject(constructor);
544 if (!maybe_object->ToObject(&object)) return maybe_object;
545 }
ager@chromium.org32912102009-01-16 10:38:43 +0000546 // Assign the exception value to the catch variable and make sure
547 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000548 { MaybeObject* maybe_value =
549 JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
550 if (!maybe_value->ToObject(&value)) return maybe_value;
551 }
ager@chromium.org32912102009-01-16 10:38:43 +0000552 return object;
553}
554
555
lrn@chromium.org303ada72010-10-27 09:33:13 +0000556static MaybeObject* Runtime_ClassOf(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 NoHandleAllocation ha;
558 ASSERT(args.length() == 1);
559 Object* obj = args[0];
560 if (!obj->IsJSObject()) return Heap::null_value();
561 return JSObject::cast(obj)->class_name();
562}
563
ager@chromium.org7c537e22008-10-16 08:43:32 +0000564
lrn@chromium.org303ada72010-10-27 09:33:13 +0000565static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 NoHandleAllocation ha;
567 ASSERT(args.length() == 2);
568 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
569 Object* O = args[0];
570 Object* V = args[1];
571 while (true) {
572 Object* prototype = V->GetPrototype();
573 if (prototype->IsNull()) return Heap::false_value();
574 if (O == prototype) return Heap::true_value();
575 V = prototype;
576 }
577}
578
579
ager@chromium.org9085a012009-05-11 19:22:57 +0000580// Inserts an object as the hidden prototype of another object.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000581static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000582 NoHandleAllocation ha;
583 ASSERT(args.length() == 2);
584 CONVERT_CHECKED(JSObject, jsobject, args[0]);
585 CONVERT_CHECKED(JSObject, proto, args[1]);
586
587 // Sanity checks. The old prototype (that we are replacing) could
588 // theoretically be null, but if it is not null then check that we
589 // didn't already install a hidden prototype here.
590 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
591 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
592 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
593
594 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000595 Object* map_or_failure;
596 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
597 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
598 return maybe_map_or_failure;
599 }
600 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000601 Map* new_proto_map = Map::cast(map_or_failure);
602
lrn@chromium.org303ada72010-10-27 09:33:13 +0000603 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
604 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
605 return maybe_map_or_failure;
606 }
607 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000608 Map* new_map = Map::cast(map_or_failure);
609
610 // Set proto's prototype to be the old prototype of the object.
611 new_proto_map->set_prototype(jsobject->GetPrototype());
612 proto->set_map(new_proto_map);
613 new_proto_map->set_is_hidden_prototype();
614
615 // Set the object's prototype to proto.
616 new_map->set_prototype(proto);
617 jsobject->set_map(new_map);
618
619 return Heap::undefined_value();
620}
621
622
lrn@chromium.org303ada72010-10-27 09:33:13 +0000623static MaybeObject* Runtime_IsConstructCall(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000625 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000626 JavaScriptFrameIterator it;
627 return Heap::ToBoolean(it.frame()->IsConstructor());
628}
629
630
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000631// Recursively traverses hidden prototypes if property is not found
632static void GetOwnPropertyImplementation(JSObject* obj,
633 String* name,
634 LookupResult* result) {
635 obj->LocalLookupRealNamedProperty(name, result);
636
637 if (!result->IsProperty()) {
638 Object* proto = obj->GetPrototype();
639 if (proto->IsJSObject() &&
640 JSObject::cast(proto)->map()->is_hidden_prototype())
641 GetOwnPropertyImplementation(JSObject::cast(proto),
642 name, result);
643 }
644}
645
646
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000647// Enumerator used as indices into the array returned from GetOwnProperty
648enum PropertyDescriptorIndices {
649 IS_ACCESSOR_INDEX,
650 VALUE_INDEX,
651 GETTER_INDEX,
652 SETTER_INDEX,
653 WRITABLE_INDEX,
654 ENUMERABLE_INDEX,
655 CONFIGURABLE_INDEX,
656 DESCRIPTOR_SIZE
657};
658
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000659// Returns an array with the property description:
660// if args[1] is not a property on args[0]
661// returns undefined
662// if args[1] is a data property on args[0]
663// [false, value, Writeable, Enumerable, Configurable]
664// if args[1] is an accessor on args[0]
665// [true, GetFunction, SetFunction, Enumerable, Configurable]
lrn@chromium.org303ada72010-10-27 09:33:13 +0000666static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000667 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000668 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000669 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000670 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
671 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000672 CONVERT_ARG_CHECKED(JSObject, obj, 0);
673 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000674
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000675 // This could be an element.
676 uint32_t index;
677 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000678 switch (obj->HasLocalElement(index)) {
679 case JSObject::UNDEFINED_ELEMENT:
680 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000681
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000682 case JSObject::STRING_CHARACTER_ELEMENT: {
683 // Special handling of string objects according to ECMAScript 5
684 // 15.5.5.2. Note that this might be a string object with elements
685 // other than the actual string value. This is covered by the
686 // subsequent cases.
687 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
688 Handle<String> str(String::cast(js_value->value()));
689 Handle<String> substr = SubString(str, index, index+1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000690
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000691 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
692 elms->set(VALUE_INDEX, *substr);
693 elms->set(WRITABLE_INDEX, Heap::false_value());
694 elms->set(ENUMERABLE_INDEX, Heap::false_value());
695 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
696 return *desc;
697 }
698
699 case JSObject::INTERCEPTED_ELEMENT:
700 case JSObject::FAST_ELEMENT: {
701 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
702 Handle<Object> element = GetElement(Handle<Object>(obj), index);
703 elms->set(VALUE_INDEX, *element);
704 elms->set(WRITABLE_INDEX, Heap::true_value());
705 elms->set(ENUMERABLE_INDEX, Heap::true_value());
706 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
707 return *desc;
708 }
709
710 case JSObject::DICTIONARY_ELEMENT: {
711 NumberDictionary* dictionary = obj->element_dictionary();
712 int entry = dictionary->FindEntry(index);
713 ASSERT(entry != NumberDictionary::kNotFound);
714 PropertyDetails details = dictionary->DetailsAt(entry);
715 switch (details.type()) {
716 case CALLBACKS: {
717 // This is an accessor property with getter and/or setter.
718 FixedArray* callbacks =
719 FixedArray::cast(dictionary->ValueAt(entry));
720 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
721 elms->set(GETTER_INDEX, callbacks->get(0));
722 elms->set(SETTER_INDEX, callbacks->get(1));
723 break;
724 }
725 case NORMAL:
726 // This is a data property.
727 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
728 elms->set(VALUE_INDEX, dictionary->ValueAt(entry));
729 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
730 break;
731 default:
732 UNREACHABLE();
733 break;
734 }
735 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
736 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
737 return *desc;
738 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000739 }
740 }
741
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000742 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000743 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000744
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000745 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000746 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000747 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000748 if (result.type() == CALLBACKS) {
749 Object* structure = result.GetCallbackObject();
ager@chromium.org5c838252010-02-19 08:53:10 +0000750 if (structure->IsProxy() || structure->IsAccessorInfo()) {
751 // Property that is internally implemented as a callback or
752 // an API defined callback.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000753 Object* value;
754 { MaybeObject* maybe_value = obj->GetPropertyWithCallback(
755 *obj, structure, *name, result.holder());
756 if (!maybe_value->ToObject(&value)) return maybe_value;
757 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000758 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
759 elms->set(VALUE_INDEX, value);
760 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000761 } else if (structure->IsFixedArray()) {
762 // __defineGetter__/__defineSetter__ callback.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000763 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
764 elms->set(GETTER_INDEX, FixedArray::cast(structure)->get(0));
765 elms->set(SETTER_INDEX, FixedArray::cast(structure)->get(1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000766 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000767 return Heap::undefined_value();
768 }
769 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000770 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
771 elms->set(VALUE_INDEX, result.GetLazyValue());
772 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000773 }
774
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000775 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
776 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000777 return *desc;
778}
779
780
lrn@chromium.org303ada72010-10-27 09:33:13 +0000781static MaybeObject* Runtime_PreventExtensions(Arguments args) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000782 ASSERT(args.length() == 1);
783 CONVERT_CHECKED(JSObject, obj, args[0]);
784 return obj->PreventExtensions();
785}
786
lrn@chromium.org303ada72010-10-27 09:33:13 +0000787static MaybeObject* Runtime_IsExtensible(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000788 ASSERT(args.length() == 1);
789 CONVERT_CHECKED(JSObject, obj, args[0]);
790 return obj->map()->is_extensible() ? Heap::true_value()
791 : Heap::false_value();
792}
793
794
lrn@chromium.org303ada72010-10-27 09:33:13 +0000795static MaybeObject* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000796 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000797 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000798 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
799 CONVERT_ARG_CHECKED(String, pattern, 1);
800 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000801 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
802 if (result.is_null()) return Failure::Exception();
803 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000804}
805
806
lrn@chromium.org303ada72010-10-27 09:33:13 +0000807static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808 HandleScope scope;
809 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000810 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000811 return *Factory::CreateApiFunction(data);
812}
813
814
lrn@chromium.org303ada72010-10-27 09:33:13 +0000815static MaybeObject* Runtime_IsTemplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000816 ASSERT(args.length() == 1);
817 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000818 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000819 return Heap::ToBoolean(result);
820}
821
822
lrn@chromium.org303ada72010-10-27 09:33:13 +0000823static MaybeObject* Runtime_GetTemplateField(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000824 ASSERT(args.length() == 2);
825 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000826 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000827 int index = field->value();
828 int offset = index * kPointerSize + HeapObject::kHeaderSize;
829 InstanceType type = templ->map()->instance_type();
830 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
831 type == OBJECT_TEMPLATE_INFO_TYPE);
832 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000833 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000834 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
835 } else {
836 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
837 }
838 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000839}
840
841
lrn@chromium.org303ada72010-10-27 09:33:13 +0000842static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000843 ASSERT(args.length() == 1);
844 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000845 Map* old_map = object->map();
846 bool needs_access_checks = old_map->is_access_check_needed();
847 if (needs_access_checks) {
848 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000849 Object* new_map;
850 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
851 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
852 }
ager@chromium.org32912102009-01-16 10:38:43 +0000853
854 Map::cast(new_map)->set_is_access_check_needed(false);
855 object->set_map(Map::cast(new_map));
856 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000857 return needs_access_checks ? Heap::true_value() : Heap::false_value();
858}
859
860
lrn@chromium.org303ada72010-10-27 09:33:13 +0000861static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000862 ASSERT(args.length() == 1);
863 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000864 Map* old_map = object->map();
865 if (!old_map->is_access_check_needed()) {
866 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000867 Object* new_map;
868 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
869 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
870 }
ager@chromium.org32912102009-01-16 10:38:43 +0000871
872 Map::cast(new_map)->set_is_access_check_needed(true);
873 object->set_map(Map::cast(new_map));
874 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000875 return Heap::undefined_value();
876}
877
878
lrn@chromium.org303ada72010-10-27 09:33:13 +0000879static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880 HandleScope scope;
881 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
882 Handle<Object> args[2] = { type_handle, name };
883 Handle<Object> error =
884 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
885 return Top::Throw(*error);
886}
887
888
lrn@chromium.org303ada72010-10-27 09:33:13 +0000889static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000890 HandleScope scope;
891 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
892
ager@chromium.org3811b432009-10-28 14:53:37 +0000893 Handle<Context> context = args.at<Context>(0);
894 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000895 bool is_eval = Smi::cast(args[2])->value() == 1;
896
897 // Compute the property attributes. According to ECMA-262, section
898 // 13, page 71, the property must be read-only and
899 // non-deletable. However, neither SpiderMonkey nor KJS creates the
900 // property as read-only, so we don't either.
901 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
902
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000903 // Traverse the name/value pairs and set the properties.
904 int length = pairs->length();
905 for (int i = 0; i < length; i += 2) {
906 HandleScope scope;
907 Handle<String> name(String::cast(pairs->get(i)));
908 Handle<Object> value(pairs->get(i + 1));
909
910 // We have to declare a global const property. To capture we only
911 // assign to it when evaluating the assignment for "const x =
912 // <expr>" the initial value is the hole.
913 bool is_const_property = value->IsTheHole();
914
915 if (value->IsUndefined() || is_const_property) {
916 // Lookup the property in the global object, and don't set the
917 // value of the variable if the property is already there.
918 LookupResult lookup;
919 global->Lookup(*name, &lookup);
920 if (lookup.IsProperty()) {
921 // Determine if the property is local by comparing the holder
922 // against the global object. The information will be used to
923 // avoid throwing re-declaration errors when declaring
924 // variables or constants that exist in the prototype chain.
925 bool is_local = (*global == lookup.holder());
926 // Get the property attributes and determine if the property is
927 // read-only.
928 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
929 bool is_read_only = (attributes & READ_ONLY) != 0;
930 if (lookup.type() == INTERCEPTOR) {
931 // If the interceptor says the property is there, we
932 // just return undefined without overwriting the property.
933 // Otherwise, we continue to setting the property.
934 if (attributes != ABSENT) {
935 // Check if the existing property conflicts with regards to const.
936 if (is_local && (is_read_only || is_const_property)) {
937 const char* type = (is_read_only) ? "const" : "var";
938 return ThrowRedeclarationError(type, name);
939 };
940 // The property already exists without conflicting: Go to
941 // the next declaration.
942 continue;
943 }
944 // Fall-through and introduce the absent property by using
945 // SetProperty.
946 } else {
947 if (is_local && (is_read_only || is_const_property)) {
948 const char* type = (is_read_only) ? "const" : "var";
949 return ThrowRedeclarationError(type, name);
950 }
951 // The property already exists without conflicting: Go to
952 // the next declaration.
953 continue;
954 }
955 }
956 } else {
957 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000958 Handle<SharedFunctionInfo> shared =
959 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000960 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000961 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000962 value = function;
963 }
964
965 LookupResult lookup;
966 global->LocalLookup(*name, &lookup);
967
968 PropertyAttributes attributes = is_const_property
969 ? static_cast<PropertyAttributes>(base | READ_ONLY)
970 : base;
971
972 if (lookup.IsProperty()) {
973 // There's a local property that we need to overwrite because
974 // we're either declaring a function or there's an interceptor
975 // that claims the property is absent.
976
977 // Check for conflicting re-declarations. We cannot have
978 // conflicting types in case of intercepted properties because
979 // they are absent.
980 if (lookup.type() != INTERCEPTOR &&
981 (lookup.IsReadOnly() || is_const_property)) {
982 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
983 return ThrowRedeclarationError(type, name);
984 }
985 SetProperty(global, name, value, attributes);
986 } else {
987 // If a property with this name does not already exist on the
988 // global object add the property locally. We take special
989 // precautions to always add it as a local property even in case
990 // of callbacks in the prototype chain (this rules out using
991 // SetProperty). Also, we must use the handle-based version to
992 // avoid GC issues.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000993 SetLocalPropertyIgnoreAttributes(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000994 }
995 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000996
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 return Heap::undefined_value();
998}
999
1000
lrn@chromium.org303ada72010-10-27 09:33:13 +00001001static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001003 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001004
ager@chromium.org7c537e22008-10-16 08:43:32 +00001005 CONVERT_ARG_CHECKED(Context, context, 0);
1006 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001008 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001009 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001010 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011
1012 // Declarations are always done in the function context.
1013 context = Handle<Context>(context->fcontext());
1014
1015 int index;
1016 PropertyAttributes attributes;
1017 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001018 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019 context->Lookup(name, flags, &index, &attributes);
1020
1021 if (attributes != ABSENT) {
1022 // The name was declared before; check for conflicting
1023 // re-declarations: This is similar to the code in parser.cc in
1024 // the AstBuildingParser::Declare function.
1025 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1026 // Functions are not read-only.
1027 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1028 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1029 return ThrowRedeclarationError(type, name);
1030 }
1031
1032 // Initialize it if necessary.
1033 if (*initial_value != NULL) {
1034 if (index >= 0) {
1035 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001036 // the function context or the arguments object.
1037 if (holder->IsContext()) {
1038 ASSERT(holder.is_identical_to(context));
1039 if (((attributes & READ_ONLY) == 0) ||
1040 context->get(index)->IsTheHole()) {
1041 context->set(index, *initial_value);
1042 }
1043 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001044 // The holder is an arguments object.
1045 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1046 SetElement(arguments, index, initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001047 }
1048 } else {
1049 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001050 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051 SetProperty(context_ext, name, initial_value, mode);
1052 }
1053 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001054
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001055 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001056 // The property is not in the function context. It needs to be
1057 // "declared" in the function context's extension context, or in the
1058 // global context.
1059 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001060 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001061 // The function context's extension context exists - use it.
1062 context_ext = Handle<JSObject>(context->extension());
1063 } else {
1064 // The function context's extension context does not exists - allocate
1065 // it.
1066 context_ext = Factory::NewJSObject(Top::context_extension_function());
1067 // And store it in the extension slot.
1068 context->set_extension(*context_ext);
1069 }
1070 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001071
ager@chromium.org7c537e22008-10-16 08:43:32 +00001072 // Declare the property by setting it to the initial value if provided,
1073 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1074 // constant declarations).
1075 ASSERT(!context_ext->HasLocalProperty(*name));
1076 Handle<Object> value(Heap::undefined_value());
1077 if (*initial_value != NULL) value = initial_value;
1078 SetProperty(context_ext, name, value, mode);
1079 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
1080 }
1081
1082 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001083}
1084
1085
lrn@chromium.org303ada72010-10-27 09:33:13 +00001086static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001087 NoHandleAllocation nha;
1088
1089 // Determine if we need to assign to the variable if it already
1090 // exists (based on the number of arguments).
1091 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1092 bool assign = args.length() == 2;
1093
1094 CONVERT_ARG_CHECKED(String, name, 0);
1095 GlobalObject* global = Top::context()->global();
1096
1097 // According to ECMA-262, section 12.2, page 62, the property must
1098 // not be deletable.
1099 PropertyAttributes attributes = DONT_DELETE;
1100
1101 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001102 // there, there is a property with this name in the prototype chain.
1103 // We follow Safari and Firefox behavior and only set the property
1104 // locally if there is an explicit initialization value that we have
1105 // to assign to the property. When adding the property we take
1106 // special precautions to always add it as a local property even in
1107 // case of callbacks in the prototype chain (this rules out using
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001108 // SetProperty). We have SetLocalPropertyIgnoreAttributes for
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001109 // this.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001110 // Note that objects can have hidden prototypes, so we need to traverse
1111 // the whole chain of hidden prototypes to do a 'local' lookup.
1112 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001113 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001114 while (true) {
1115 real_holder->LocalLookup(*name, &lookup);
1116 if (lookup.IsProperty()) {
1117 // Determine if this is a redeclaration of something read-only.
1118 if (lookup.IsReadOnly()) {
1119 // If we found readonly property on one of hidden prototypes,
1120 // just shadow it.
1121 if (real_holder != Top::context()->global()) break;
1122 return ThrowRedeclarationError("const", name);
1123 }
1124
1125 // Determine if this is a redeclaration of an intercepted read-only
1126 // property and figure out if the property exists at all.
1127 bool found = true;
1128 PropertyType type = lookup.type();
1129 if (type == INTERCEPTOR) {
1130 HandleScope handle_scope;
1131 Handle<JSObject> holder(real_holder);
1132 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1133 real_holder = *holder;
1134 if (intercepted == ABSENT) {
1135 // The interceptor claims the property isn't there. We need to
1136 // make sure to introduce it.
1137 found = false;
1138 } else if ((intercepted & READ_ONLY) != 0) {
1139 // The property is present, but read-only. Since we're trying to
1140 // overwrite it with a variable declaration we must throw a
1141 // re-declaration error. However if we found readonly property
1142 // on one of hidden prototypes, just shadow it.
1143 if (real_holder != Top::context()->global()) break;
1144 return ThrowRedeclarationError("const", name);
1145 }
1146 }
1147
1148 if (found && !assign) {
1149 // The global property is there and we're not assigning any value
1150 // to it. Just return.
1151 return Heap::undefined_value();
1152 }
1153
1154 // Assign the value (or undefined) to the property.
1155 Object* value = (assign) ? args[1] : Heap::undefined_value();
1156 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001157 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001158
1159 Object* proto = real_holder->GetPrototype();
1160 if (!proto->IsJSObject())
1161 break;
1162
1163 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1164 break;
1165
1166 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001167 }
1168
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001169 global = Top::context()->global();
1170 if (assign) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001171 return global->SetLocalPropertyIgnoreAttributes(*name,
1172 args[1],
1173 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001175 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176}
1177
1178
lrn@chromium.org303ada72010-10-27 09:33:13 +00001179static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001180 // All constants are declared with an initial value. The name
1181 // of the constant is the first argument and the initial value
1182 // is the second.
1183 RUNTIME_ASSERT(args.length() == 2);
1184 CONVERT_ARG_CHECKED(String, name, 0);
1185 Handle<Object> value = args.at<Object>(1);
1186
1187 // Get the current global object from top.
1188 GlobalObject* global = Top::context()->global();
1189
1190 // According to ECMA-262, section 12.2, page 62, the property must
1191 // not be deletable. Since it's a const, it must be READ_ONLY too.
1192 PropertyAttributes attributes =
1193 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1194
1195 // Lookup the property locally in the global object. If it isn't
1196 // there, we add the property and take special precautions to always
1197 // add it as a local property even in case of callbacks in the
1198 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001199 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200 LookupResult lookup;
1201 global->LocalLookup(*name, &lookup);
1202 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001203 return global->SetLocalPropertyIgnoreAttributes(*name,
1204 *value,
1205 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001206 }
1207
1208 // Determine if this is a redeclaration of something not
1209 // read-only. In case the result is hidden behind an interceptor we
1210 // need to ask it for the property attributes.
1211 if (!lookup.IsReadOnly()) {
1212 if (lookup.type() != INTERCEPTOR) {
1213 return ThrowRedeclarationError("var", name);
1214 }
1215
1216 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1217
1218 // Throw re-declaration error if the intercepted property is present
1219 // but not read-only.
1220 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1221 return ThrowRedeclarationError("var", name);
1222 }
1223
1224 // Restore global object from context (in case of GC) and continue
1225 // with setting the value because the property is either absent or
1226 // read-only. We also have to do redo the lookup.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001227 HandleScope handle_scope;
1228 Handle<GlobalObject>global(Top::context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001229
1230 // BUG 1213579: Handle the case where we have to set a read-only
1231 // property through an interceptor and only do it if it's
1232 // uninitialized, e.g. the hole. Nirk...
lrn@chromium.org303ada72010-10-27 09:33:13 +00001233 SetProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234 return *value;
1235 }
1236
1237 // Set the value, but only we're assigning the initial value to a
1238 // constant. For now, we determine this by checking if the
1239 // current value is the hole.
1240 PropertyType type = lookup.type();
1241 if (type == FIELD) {
1242 FixedArray* properties = global->properties();
1243 int index = lookup.GetFieldIndex();
1244 if (properties->get(index)->IsTheHole()) {
1245 properties->set(index, *value);
1246 }
1247 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001248 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1249 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001250 }
1251 } else {
1252 // Ignore re-initialization of constants that have already been
1253 // assigned a function value.
1254 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1255 }
1256
1257 // Use the set value as the result of the operation.
1258 return *value;
1259}
1260
1261
lrn@chromium.org303ada72010-10-27 09:33:13 +00001262static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001263 HandleScope scope;
1264 ASSERT(args.length() == 3);
1265
1266 Handle<Object> value(args[0]);
1267 ASSERT(!value->IsTheHole());
1268 CONVERT_ARG_CHECKED(Context, context, 1);
1269 Handle<String> name(String::cast(args[2]));
1270
1271 // Initializations are always done in the function context.
1272 context = Handle<Context>(context->fcontext());
1273
1274 int index;
1275 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001276 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001277 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 context->Lookup(name, flags, &index, &attributes);
1279
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001280 // In most situations, the property introduced by the const
1281 // declaration should be present in the context extension object.
1282 // However, because declaration and initialization are separate, the
1283 // property might have been deleted (if it was introduced by eval)
1284 // before we reach the initialization point.
1285 //
1286 // Example:
1287 //
1288 // function f() { eval("delete x; const x;"); }
1289 //
1290 // In that case, the initialization behaves like a normal assignment
1291 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001292 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001293 // Property was found in a context.
1294 if (holder->IsContext()) {
1295 // The holder cannot be the function context. If it is, there
1296 // should have been a const redeclaration error when declaring
1297 // the const property.
1298 ASSERT(!holder.is_identical_to(context));
1299 if ((attributes & READ_ONLY) == 0) {
1300 Handle<Context>::cast(holder)->set(index, *value);
1301 }
1302 } else {
1303 // The holder is an arguments object.
1304 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001305 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1306 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307 }
1308 return *value;
1309 }
1310
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001311 // The property could not be found, we introduce it in the global
1312 // context.
1313 if (attributes == ABSENT) {
1314 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
1315 SetProperty(global, name, value, NONE);
1316 return *value;
1317 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001318
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001319 // The property was present in a context extension object.
1320 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001322 if (*context_ext == context->extension()) {
1323 // This is the property that was introduced by the const
1324 // declaration. Set it if it hasn't been set before. NOTE: We
1325 // cannot use GetProperty() to get the current value as it
1326 // 'unholes' the value.
1327 LookupResult lookup;
1328 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1329 ASSERT(lookup.IsProperty()); // the property was declared
1330 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1331
1332 PropertyType type = lookup.type();
1333 if (type == FIELD) {
1334 FixedArray* properties = context_ext->properties();
1335 int index = lookup.GetFieldIndex();
1336 if (properties->get(index)->IsTheHole()) {
1337 properties->set(index, *value);
1338 }
1339 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001340 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1341 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001342 }
1343 } else {
1344 // We should not reach here. Any real, named property should be
1345 // either a field or a dictionary slot.
1346 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347 }
1348 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001349 // The property was found in a different context extension object.
1350 // Set it if it is not a read-only property.
1351 if ((attributes & READ_ONLY) == 0) {
1352 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
1353 // Setting a property might throw an exception. Exceptions
1354 // are converted to empty handles in handle operations. We
1355 // need to convert back to exceptions here.
1356 if (set.is_null()) {
1357 ASSERT(Top::has_pending_exception());
1358 return Failure::Exception();
1359 }
1360 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001362
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001363 return *value;
1364}
1365
1366
lrn@chromium.org303ada72010-10-27 09:33:13 +00001367static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001368 Arguments args) {
1369 HandleScope scope;
1370 ASSERT(args.length() == 2);
1371 CONVERT_ARG_CHECKED(JSObject, object, 0);
1372 CONVERT_SMI_CHECKED(properties, args[1]);
1373 if (object->HasFastProperties()) {
1374 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1375 }
1376 return *object;
1377}
1378
1379
lrn@chromium.org303ada72010-10-27 09:33:13 +00001380static MaybeObject* Runtime_RegExpExec(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001381 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001382 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001383 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1384 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001385 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001386 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001387 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001388 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001389 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001390 RUNTIME_ASSERT(index >= 0);
1391 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001392 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001393 Handle<Object> result = RegExpImpl::Exec(regexp,
1394 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001395 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001396 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001397 if (result.is_null()) return Failure::Exception();
1398 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399}
1400
1401
lrn@chromium.org303ada72010-10-27 09:33:13 +00001402static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001403 ASSERT(args.length() == 3);
1404 CONVERT_SMI_CHECKED(elements_count, args[0]);
1405 if (elements_count > JSArray::kMaxFastElementsLength) {
1406 return Top::ThrowIllegalOperation();
1407 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001408 Object* new_object;
1409 { MaybeObject* maybe_new_object =
1410 Heap::AllocateFixedArrayWithHoles(elements_count);
1411 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1412 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001413 FixedArray* elements = FixedArray::cast(new_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001414 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1415 NEW_SPACE,
1416 OLD_POINTER_SPACE);
1417 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1418 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001419 {
1420 AssertNoAllocation no_gc;
1421 HandleScope scope;
1422 reinterpret_cast<HeapObject*>(new_object)->
1423 set_map(Top::global_context()->regexp_result_map());
1424 }
1425 JSArray* array = JSArray::cast(new_object);
1426 array->set_properties(Heap::empty_fixed_array());
1427 array->set_elements(elements);
1428 array->set_length(Smi::FromInt(elements_count));
1429 // Write in-object properties after the length of the array.
1430 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1431 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1432 return array;
1433}
1434
1435
lrn@chromium.org303ada72010-10-27 09:33:13 +00001436static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001437 AssertNoAllocation no_alloc;
1438 ASSERT(args.length() == 5);
1439 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1440 CONVERT_CHECKED(String, source, args[1]);
1441
1442 Object* global = args[2];
1443 if (!global->IsTrue()) global = Heap::false_value();
1444
1445 Object* ignoreCase = args[3];
1446 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1447
1448 Object* multiline = args[4];
1449 if (!multiline->IsTrue()) multiline = Heap::false_value();
1450
1451 Map* map = regexp->map();
1452 Object* constructor = map->constructor();
1453 if (constructor->IsJSFunction() &&
1454 JSFunction::cast(constructor)->initial_map() == map) {
1455 // If we still have the original map, set in-object properties directly.
1456 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1457 // TODO(lrn): Consider skipping write barrier on booleans as well.
1458 // Both true and false should be in oldspace at all times.
1459 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1460 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1461 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1462 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1463 Smi::FromInt(0),
1464 SKIP_WRITE_BARRIER);
1465 return regexp;
1466 }
1467
lrn@chromium.org303ada72010-10-27 09:33:13 +00001468 // Map has changed, so use generic, but slower, method. Since these
1469 // properties were all added as DONT_DELETE they must be present and
1470 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001471 PropertyAttributes final =
1472 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1473 PropertyAttributes writable =
1474 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001475 MaybeObject* result;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001476 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::source_symbol(),
1477 source,
1478 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001479 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001480 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::global_symbol(),
1481 global,
1482 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001483 ASSERT(!result->IsFailure());
1484 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001485 regexp->SetLocalPropertyIgnoreAttributes(Heap::ignore_case_symbol(),
1486 ignoreCase,
1487 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001488 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001489 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::multiline_symbol(),
1490 multiline,
1491 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001492 ASSERT(!result->IsFailure());
1493 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001494 regexp->SetLocalPropertyIgnoreAttributes(Heap::last_index_symbol(),
1495 Smi::FromInt(0),
1496 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001497 ASSERT(!result->IsFailure());
1498 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001499 return regexp;
1500}
1501
1502
lrn@chromium.org303ada72010-10-27 09:33:13 +00001503static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001504 HandleScope scope;
1505 ASSERT(args.length() == 1);
1506 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1507 // This is necessary to enable fast checks for absence of elements
1508 // on Array.prototype and below.
1509 prototype->set_elements(Heap::empty_fixed_array());
1510 return Smi::FromInt(0);
1511}
1512
1513
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001514static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1515 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001516 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001517 Handle<String> key = Factory::LookupAsciiSymbol(name);
1518 Handle<Code> code(Builtins::builtin(builtin_name));
1519 Handle<JSFunction> optimized = Factory::NewFunction(key,
1520 JS_OBJECT_TYPE,
1521 JSObject::kHeaderSize,
1522 code,
1523 false);
1524 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001525 SetProperty(holder, key, optimized, NONE);
1526 return optimized;
1527}
1528
1529
lrn@chromium.org303ada72010-10-27 09:33:13 +00001530static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001531 HandleScope scope;
1532 ASSERT(args.length() == 1);
1533 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1534
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001535 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1536 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001537 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1538 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1539 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1540 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001541 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001542
1543 return *holder;
1544}
1545
1546
lrn@chromium.org303ada72010-10-27 09:33:13 +00001547static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001548 // Returns a real global receiver, not one of builtins object.
1549 Context* global_context = Top::context()->global()->global_context();
1550 return global_context->global()->global_receiver();
1551}
1552
1553
lrn@chromium.org303ada72010-10-27 09:33:13 +00001554static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555 HandleScope scope;
1556 ASSERT(args.length() == 4);
1557 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1558 int index = Smi::cast(args[1])->value();
1559 Handle<String> pattern = args.at<String>(2);
1560 Handle<String> flags = args.at<String>(3);
1561
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001562 // Get the RegExp function from the context in the literals array.
1563 // This is the RegExp function from the context in which the
1564 // function was created. We do not use the RegExp function from the
1565 // current global context because this might be the RegExp function
1566 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001567 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001568 Handle<JSFunction>(
1569 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001570 // Compute the regular expression literal.
1571 bool has_pending_exception;
1572 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001573 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1574 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001575 if (has_pending_exception) {
1576 ASSERT(Top::has_pending_exception());
1577 return Failure::Exception();
1578 }
1579 literals->set(index, *regexp);
1580 return *regexp;
1581}
1582
1583
lrn@chromium.org303ada72010-10-27 09:33:13 +00001584static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585 NoHandleAllocation ha;
1586 ASSERT(args.length() == 1);
1587
1588 CONVERT_CHECKED(JSFunction, f, args[0]);
1589 return f->shared()->name();
1590}
1591
1592
lrn@chromium.org303ada72010-10-27 09:33:13 +00001593static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001594 NoHandleAllocation ha;
1595 ASSERT(args.length() == 2);
1596
1597 CONVERT_CHECKED(JSFunction, f, args[0]);
1598 CONVERT_CHECKED(String, name, args[1]);
1599 f->shared()->set_name(name);
1600 return Heap::undefined_value();
1601}
1602
1603
lrn@chromium.org303ada72010-10-27 09:33:13 +00001604static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001605 NoHandleAllocation ha;
1606 ASSERT(args.length() == 1);
1607
1608 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001609 Object* obj;
1610 { MaybeObject* maybe_obj = f->RemovePrototype();
1611 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1612 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001613
1614 return Heap::undefined_value();
1615}
1616
1617
lrn@chromium.org303ada72010-10-27 09:33:13 +00001618static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001619 HandleScope scope;
1620 ASSERT(args.length() == 1);
1621
1622 CONVERT_CHECKED(JSFunction, fun, args[0]);
1623 Handle<Object> script = Handle<Object>(fun->shared()->script());
1624 if (!script->IsScript()) return Heap::undefined_value();
1625
1626 return *GetScriptWrapper(Handle<Script>::cast(script));
1627}
1628
1629
lrn@chromium.org303ada72010-10-27 09:33:13 +00001630static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631 NoHandleAllocation ha;
1632 ASSERT(args.length() == 1);
1633
1634 CONVERT_CHECKED(JSFunction, f, args[0]);
1635 return f->shared()->GetSourceCode();
1636}
1637
1638
lrn@chromium.org303ada72010-10-27 09:33:13 +00001639static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001640 NoHandleAllocation ha;
1641 ASSERT(args.length() == 1);
1642
1643 CONVERT_CHECKED(JSFunction, fun, args[0]);
1644 int pos = fun->shared()->start_position();
1645 return Smi::FromInt(pos);
1646}
1647
1648
lrn@chromium.org303ada72010-10-27 09:33:13 +00001649static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001650 ASSERT(args.length() == 2);
1651
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001652 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001653 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1654
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001655 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1656
1657 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001658 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001659}
1660
1661
1662
lrn@chromium.org303ada72010-10-27 09:33:13 +00001663static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001664 NoHandleAllocation ha;
1665 ASSERT(args.length() == 2);
1666
1667 CONVERT_CHECKED(JSFunction, fun, args[0]);
1668 CONVERT_CHECKED(String, name, args[1]);
1669 fun->SetInstanceClassName(name);
1670 return Heap::undefined_value();
1671}
1672
1673
lrn@chromium.org303ada72010-10-27 09:33:13 +00001674static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001675 NoHandleAllocation ha;
1676 ASSERT(args.length() == 2);
1677
1678 CONVERT_CHECKED(JSFunction, fun, args[0]);
1679 CONVERT_CHECKED(Smi, length, args[1]);
1680 fun->shared()->set_length(length->value());
1681 return length;
1682}
1683
1684
lrn@chromium.org303ada72010-10-27 09:33:13 +00001685static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001686 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001687 ASSERT(args.length() == 2);
1688
1689 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001690 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001691 Object* obj;
1692 { MaybeObject* maybe_obj =
1693 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1694 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1695 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001696 return args[0]; // return TOS
1697}
1698
1699
lrn@chromium.org303ada72010-10-27 09:33:13 +00001700static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001701 NoHandleAllocation ha;
1702 ASSERT(args.length() == 1);
1703
1704 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001705 return f->shared()->IsApiFunction() ? Heap::true_value()
1706 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001707}
1708
lrn@chromium.org303ada72010-10-27 09:33:13 +00001709static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001710 NoHandleAllocation ha;
1711 ASSERT(args.length() == 1);
1712
1713 CONVERT_CHECKED(JSFunction, f, args[0]);
1714 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1715}
1716
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001717
lrn@chromium.org303ada72010-10-27 09:33:13 +00001718static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719 HandleScope scope;
1720 ASSERT(args.length() == 2);
1721
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001722 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001723 Handle<Object> code = args.at<Object>(1);
1724
1725 Handle<Context> context(target->context());
1726
1727 if (!code->IsNull()) {
1728 RUNTIME_ASSERT(code->IsJSFunction());
1729 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001730 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001731
1732 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001733 return Failure::Exception();
1734 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001735 // Since we don't store the source for this we should never
1736 // optimize this.
1737 shared->code()->set_optimizable(false);
1738
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001739 // Set the code, scope info, formal parameter count,
1740 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001741 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001742 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001743 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001744 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001745 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001746 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001747 // Set the source code of the target function to undefined.
1748 // SetCode is only used for built-in constructors like String,
1749 // Array, and Object, and some web code
1750 // doesn't like seeing source code for constructors.
1751 target->shared()->set_script(Heap::undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001752 // Clear the optimization hints related to the compiled code as these are no
1753 // longer valid when the code is overwritten.
1754 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001755 context = Handle<Context>(fun->context());
1756
1757 // Make sure we get a fresh copy of the literal vector to avoid
1758 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001759 int number_of_literals = fun->NumberOfLiterals();
1760 Handle<FixedArray> literals =
1761 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001762 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001763 // Insert the object, regexp and array functions in the literals
1764 // array prefix. These are the functions that will be used when
1765 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001766 literals->set(JSFunction::kLiteralGlobalContextIndex,
1767 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001768 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001769 // It's okay to skip the write barrier here because the literals
1770 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001771 target->set_literals(*literals, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001772 target->set_next_function_link(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001773 }
1774
1775 target->set_context(*context);
1776 return *target;
1777}
1778
1779
lrn@chromium.org303ada72010-10-27 09:33:13 +00001780static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001781 HandleScope scope;
1782 ASSERT(args.length() == 2);
1783 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1784 CONVERT_SMI_CHECKED(num, args[1]);
1785 RUNTIME_ASSERT(num >= 0);
1786 SetExpectedNofProperties(function, num);
1787 return Heap::undefined_value();
1788}
1789
1790
lrn@chromium.org303ada72010-10-27 09:33:13 +00001791MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001792 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001793 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001794 if (code <= 0xffff) {
1795 return Heap::LookupSingleCharacterStringFromCode(code);
1796 }
1797 }
1798 return Heap::empty_string();
1799}
1800
1801
lrn@chromium.org303ada72010-10-27 09:33:13 +00001802static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001803 NoHandleAllocation ha;
1804 ASSERT(args.length() == 2);
1805
1806 CONVERT_CHECKED(String, subject, args[0]);
1807 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001808 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001809
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001810 uint32_t i = 0;
1811 if (index->IsSmi()) {
1812 int value = Smi::cast(index)->value();
1813 if (value < 0) return Heap::nan_value();
1814 i = value;
1815 } else {
1816 ASSERT(index->IsHeapNumber());
1817 double value = HeapNumber::cast(index)->value();
1818 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001819 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001820
1821 // Flatten the string. If someone wants to get a char at an index
1822 // in a cons string, it is likely that more indices will be
1823 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001824 Object* flat;
1825 { MaybeObject* maybe_flat = subject->TryFlatten();
1826 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
1827 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001828 subject = String::cast(flat);
1829
1830 if (i >= static_cast<uint32_t>(subject->length())) {
1831 return Heap::nan_value();
1832 }
1833
1834 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001835}
1836
1837
lrn@chromium.org303ada72010-10-27 09:33:13 +00001838static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001839 NoHandleAllocation ha;
1840 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001841 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001842}
1843
lrn@chromium.org25156de2010-04-06 13:10:27 +00001844
1845class FixedArrayBuilder {
1846 public:
1847 explicit FixedArrayBuilder(int initial_capacity)
1848 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1849 length_(0) {
1850 // Require a non-zero initial size. Ensures that doubling the size to
1851 // extend the array will work.
1852 ASSERT(initial_capacity > 0);
1853 }
1854
1855 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1856 : array_(backing_store),
1857 length_(0) {
1858 // Require a non-zero initial size. Ensures that doubling the size to
1859 // extend the array will work.
1860 ASSERT(backing_store->length() > 0);
1861 }
1862
1863 bool HasCapacity(int elements) {
1864 int length = array_->length();
1865 int required_length = length_ + elements;
1866 return (length >= required_length);
1867 }
1868
1869 void EnsureCapacity(int elements) {
1870 int length = array_->length();
1871 int required_length = length_ + elements;
1872 if (length < required_length) {
1873 int new_length = length;
1874 do {
1875 new_length *= 2;
1876 } while (new_length < required_length);
1877 Handle<FixedArray> extended_array =
1878 Factory::NewFixedArrayWithHoles(new_length);
1879 array_->CopyTo(0, *extended_array, 0, length_);
1880 array_ = extended_array;
1881 }
1882 }
1883
1884 void Add(Object* value) {
1885 ASSERT(length_ < capacity());
1886 array_->set(length_, value);
1887 length_++;
1888 }
1889
1890 void Add(Smi* value) {
1891 ASSERT(length_ < capacity());
1892 array_->set(length_, value);
1893 length_++;
1894 }
1895
1896 Handle<FixedArray> array() {
1897 return array_;
1898 }
1899
1900 int length() {
1901 return length_;
1902 }
1903
1904 int capacity() {
1905 return array_->length();
1906 }
1907
1908 Handle<JSArray> ToJSArray() {
1909 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
1910 result_array->set_length(Smi::FromInt(length_));
1911 return result_array;
1912 }
1913
1914 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
1915 target_array->set_elements(*array_);
1916 target_array->set_length(Smi::FromInt(length_));
1917 return target_array;
1918 }
1919
1920 private:
1921 Handle<FixedArray> array_;
1922 int length_;
1923};
1924
1925
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001926// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001927const int kStringBuilderConcatHelperLengthBits = 11;
1928const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001929
1930template <typename schar>
1931static inline void StringBuilderConcatHelper(String*,
1932 schar*,
1933 FixedArray*,
1934 int);
1935
lrn@chromium.org25156de2010-04-06 13:10:27 +00001936typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
1937 StringBuilderSubstringLength;
1938typedef BitField<int,
1939 kStringBuilderConcatHelperLengthBits,
1940 kStringBuilderConcatHelperPositionBits>
1941 StringBuilderSubstringPosition;
1942
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001943
1944class ReplacementStringBuilder {
1945 public:
1946 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00001947 : array_builder_(estimated_part_count),
1948 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001949 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001950 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001951 // Require a non-zero initial size. Ensures that doubling the size to
1952 // extend the array will work.
1953 ASSERT(estimated_part_count > 0);
1954 }
1955
lrn@chromium.org25156de2010-04-06 13:10:27 +00001956 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
1957 int from,
1958 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001959 ASSERT(from >= 0);
1960 int length = to - from;
1961 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001962 if (StringBuilderSubstringLength::is_valid(length) &&
1963 StringBuilderSubstringPosition::is_valid(from)) {
1964 int encoded_slice = StringBuilderSubstringLength::encode(length) |
1965 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001966 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001967 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001968 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001969 builder->Add(Smi::FromInt(-length));
1970 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001971 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00001972 }
1973
1974
1975 void EnsureCapacity(int elements) {
1976 array_builder_.EnsureCapacity(elements);
1977 }
1978
1979
1980 void AddSubjectSlice(int from, int to) {
1981 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001982 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001983 }
1984
1985
1986 void AddString(Handle<String> string) {
1987 int length = string->length();
1988 ASSERT(length > 0);
1989 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00001990 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001991 is_ascii_ = false;
1992 }
1993 IncrementCharacterCount(length);
1994 }
1995
1996
1997 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001998 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001999 return Factory::empty_string();
2000 }
2001
2002 Handle<String> joined_string;
2003 if (is_ascii_) {
2004 joined_string = NewRawAsciiString(character_count_);
2005 AssertNoAllocation no_alloc;
2006 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2007 char* char_buffer = seq->GetChars();
2008 StringBuilderConcatHelper(*subject_,
2009 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002010 *array_builder_.array(),
2011 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002012 } else {
2013 // Non-ASCII.
2014 joined_string = NewRawTwoByteString(character_count_);
2015 AssertNoAllocation no_alloc;
2016 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2017 uc16* char_buffer = seq->GetChars();
2018 StringBuilderConcatHelper(*subject_,
2019 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002020 *array_builder_.array(),
2021 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002022 }
2023 return joined_string;
2024 }
2025
2026
2027 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002028 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002029 V8::FatalProcessOutOfMemory("String.replace result too large.");
2030 }
2031 character_count_ += by;
2032 }
2033
lrn@chromium.org25156de2010-04-06 13:10:27 +00002034 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002035 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002036 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002037
lrn@chromium.org25156de2010-04-06 13:10:27 +00002038 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002039 Handle<String> NewRawAsciiString(int size) {
2040 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2041 }
2042
2043
2044 Handle<String> NewRawTwoByteString(int size) {
2045 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2046 }
2047
2048
2049 void AddElement(Object* element) {
2050 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002051 ASSERT(array_builder_.capacity() > array_builder_.length());
2052 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002053 }
2054
lrn@chromium.org25156de2010-04-06 13:10:27 +00002055 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002056 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002057 int character_count_;
2058 bool is_ascii_;
2059};
2060
2061
2062class CompiledReplacement {
2063 public:
2064 CompiledReplacement()
2065 : parts_(1), replacement_substrings_(0) {}
2066
2067 void Compile(Handle<String> replacement,
2068 int capture_count,
2069 int subject_length);
2070
2071 void Apply(ReplacementStringBuilder* builder,
2072 int match_from,
2073 int match_to,
2074 Handle<JSArray> last_match_info);
2075
2076 // Number of distinct parts of the replacement pattern.
2077 int parts() {
2078 return parts_.length();
2079 }
2080 private:
2081 enum PartType {
2082 SUBJECT_PREFIX = 1,
2083 SUBJECT_SUFFIX,
2084 SUBJECT_CAPTURE,
2085 REPLACEMENT_SUBSTRING,
2086 REPLACEMENT_STRING,
2087
2088 NUMBER_OF_PART_TYPES
2089 };
2090
2091 struct ReplacementPart {
2092 static inline ReplacementPart SubjectMatch() {
2093 return ReplacementPart(SUBJECT_CAPTURE, 0);
2094 }
2095 static inline ReplacementPart SubjectCapture(int capture_index) {
2096 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2097 }
2098 static inline ReplacementPart SubjectPrefix() {
2099 return ReplacementPart(SUBJECT_PREFIX, 0);
2100 }
2101 static inline ReplacementPart SubjectSuffix(int subject_length) {
2102 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2103 }
2104 static inline ReplacementPart ReplacementString() {
2105 return ReplacementPart(REPLACEMENT_STRING, 0);
2106 }
2107 static inline ReplacementPart ReplacementSubString(int from, int to) {
2108 ASSERT(from >= 0);
2109 ASSERT(to > from);
2110 return ReplacementPart(-from, to);
2111 }
2112
2113 // If tag <= 0 then it is the negation of a start index of a substring of
2114 // the replacement pattern, otherwise it's a value from PartType.
2115 ReplacementPart(int tag, int data)
2116 : tag(tag), data(data) {
2117 // Must be non-positive or a PartType value.
2118 ASSERT(tag < NUMBER_OF_PART_TYPES);
2119 }
2120 // Either a value of PartType or a non-positive number that is
2121 // the negation of an index into the replacement string.
2122 int tag;
2123 // The data value's interpretation depends on the value of tag:
2124 // tag == SUBJECT_PREFIX ||
2125 // tag == SUBJECT_SUFFIX: data is unused.
2126 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2127 // tag == REPLACEMENT_SUBSTRING ||
2128 // tag == REPLACEMENT_STRING: data is index into array of substrings
2129 // of the replacement string.
2130 // tag <= 0: Temporary representation of the substring of the replacement
2131 // string ranging over -tag .. data.
2132 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2133 // substring objects.
2134 int data;
2135 };
2136
2137 template<typename Char>
2138 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2139 Vector<Char> characters,
2140 int capture_count,
2141 int subject_length) {
2142 int length = characters.length();
2143 int last = 0;
2144 for (int i = 0; i < length; i++) {
2145 Char c = characters[i];
2146 if (c == '$') {
2147 int next_index = i + 1;
2148 if (next_index == length) { // No next character!
2149 break;
2150 }
2151 Char c2 = characters[next_index];
2152 switch (c2) {
2153 case '$':
2154 if (i > last) {
2155 // There is a substring before. Include the first "$".
2156 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2157 last = next_index + 1; // Continue after the second "$".
2158 } else {
2159 // Let the next substring start with the second "$".
2160 last = next_index;
2161 }
2162 i = next_index;
2163 break;
2164 case '`':
2165 if (i > last) {
2166 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2167 }
2168 parts->Add(ReplacementPart::SubjectPrefix());
2169 i = next_index;
2170 last = i + 1;
2171 break;
2172 case '\'':
2173 if (i > last) {
2174 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2175 }
2176 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2177 i = next_index;
2178 last = i + 1;
2179 break;
2180 case '&':
2181 if (i > last) {
2182 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2183 }
2184 parts->Add(ReplacementPart::SubjectMatch());
2185 i = next_index;
2186 last = i + 1;
2187 break;
2188 case '0':
2189 case '1':
2190 case '2':
2191 case '3':
2192 case '4':
2193 case '5':
2194 case '6':
2195 case '7':
2196 case '8':
2197 case '9': {
2198 int capture_ref = c2 - '0';
2199 if (capture_ref > capture_count) {
2200 i = next_index;
2201 continue;
2202 }
2203 int second_digit_index = next_index + 1;
2204 if (second_digit_index < length) {
2205 // Peek ahead to see if we have two digits.
2206 Char c3 = characters[second_digit_index];
2207 if ('0' <= c3 && c3 <= '9') { // Double digits.
2208 int double_digit_ref = capture_ref * 10 + c3 - '0';
2209 if (double_digit_ref <= capture_count) {
2210 next_index = second_digit_index;
2211 capture_ref = double_digit_ref;
2212 }
2213 }
2214 }
2215 if (capture_ref > 0) {
2216 if (i > last) {
2217 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2218 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002219 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002220 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2221 last = next_index + 1;
2222 }
2223 i = next_index;
2224 break;
2225 }
2226 default:
2227 i = next_index;
2228 break;
2229 }
2230 }
2231 }
2232 if (length > last) {
2233 if (last == 0) {
2234 parts->Add(ReplacementPart::ReplacementString());
2235 } else {
2236 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2237 }
2238 }
2239 }
2240
2241 ZoneList<ReplacementPart> parts_;
2242 ZoneList<Handle<String> > replacement_substrings_;
2243};
2244
2245
2246void CompiledReplacement::Compile(Handle<String> replacement,
2247 int capture_count,
2248 int subject_length) {
2249 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002250 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002251 AssertNoAllocation no_alloc;
2252 ParseReplacementPattern(&parts_,
2253 replacement->ToAsciiVector(),
2254 capture_count,
2255 subject_length);
2256 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002257 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002258 AssertNoAllocation no_alloc;
2259
2260 ParseReplacementPattern(&parts_,
2261 replacement->ToUC16Vector(),
2262 capture_count,
2263 subject_length);
2264 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002265 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002266 int substring_index = 0;
2267 for (int i = 0, n = parts_.length(); i < n; i++) {
2268 int tag = parts_[i].tag;
2269 if (tag <= 0) { // A replacement string slice.
2270 int from = -tag;
2271 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002272 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002273 parts_[i].tag = REPLACEMENT_SUBSTRING;
2274 parts_[i].data = substring_index;
2275 substring_index++;
2276 } else if (tag == REPLACEMENT_STRING) {
2277 replacement_substrings_.Add(replacement);
2278 parts_[i].data = substring_index;
2279 substring_index++;
2280 }
2281 }
2282}
2283
2284
2285void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2286 int match_from,
2287 int match_to,
2288 Handle<JSArray> last_match_info) {
2289 for (int i = 0, n = parts_.length(); i < n; i++) {
2290 ReplacementPart part = parts_[i];
2291 switch (part.tag) {
2292 case SUBJECT_PREFIX:
2293 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2294 break;
2295 case SUBJECT_SUFFIX: {
2296 int subject_length = part.data;
2297 if (match_to < subject_length) {
2298 builder->AddSubjectSlice(match_to, subject_length);
2299 }
2300 break;
2301 }
2302 case SUBJECT_CAPTURE: {
2303 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002304 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002305 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2306 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2307 if (from >= 0 && to > from) {
2308 builder->AddSubjectSlice(from, to);
2309 }
2310 break;
2311 }
2312 case REPLACEMENT_SUBSTRING:
2313 case REPLACEMENT_STRING:
2314 builder->AddString(replacement_substrings_[part.data]);
2315 break;
2316 default:
2317 UNREACHABLE();
2318 }
2319 }
2320}
2321
2322
2323
lrn@chromium.org303ada72010-10-27 09:33:13 +00002324MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2325 String* subject,
2326 JSRegExp* regexp,
2327 String* replacement,
2328 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002329 ASSERT(subject->IsFlat());
2330 ASSERT(replacement->IsFlat());
2331
2332 HandleScope handles;
2333
2334 int length = subject->length();
2335 Handle<String> subject_handle(subject);
2336 Handle<JSRegExp> regexp_handle(regexp);
2337 Handle<String> replacement_handle(replacement);
2338 Handle<JSArray> last_match_info_handle(last_match_info);
2339 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2340 subject_handle,
2341 0,
2342 last_match_info_handle);
2343 if (match.is_null()) {
2344 return Failure::Exception();
2345 }
2346 if (match->IsNull()) {
2347 return *subject_handle;
2348 }
2349
2350 int capture_count = regexp_handle->CaptureCount();
2351
2352 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002353 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002354 CompiledReplacement compiled_replacement;
2355 compiled_replacement.Compile(replacement_handle,
2356 capture_count,
2357 length);
2358
2359 bool is_global = regexp_handle->GetFlags().is_global();
2360
2361 // Guessing the number of parts that the final result string is built
2362 // from. Global regexps can match any number of times, so we guess
2363 // conservatively.
2364 int expected_parts =
2365 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2366 ReplacementStringBuilder builder(subject_handle, expected_parts);
2367
2368 // Index of end of last match.
2369 int prev = 0;
2370
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002371 // Number of parts added by compiled replacement plus preceeding
2372 // string and possibly suffix after last match. It is possible for
2373 // all components to use two elements when encoded as two smis.
2374 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002375 bool matched = true;
2376 do {
2377 ASSERT(last_match_info_handle->HasFastElements());
2378 // Increase the capacity of the builder before entering local handle-scope,
2379 // so its internal buffer can safely allocate a new handle if it grows.
2380 builder.EnsureCapacity(parts_added_per_loop);
2381
2382 HandleScope loop_scope;
2383 int start, end;
2384 {
2385 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002386 FixedArray* match_info_array =
2387 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002388
2389 ASSERT_EQ(capture_count * 2 + 2,
2390 RegExpImpl::GetLastCaptureCount(match_info_array));
2391 start = RegExpImpl::GetCapture(match_info_array, 0);
2392 end = RegExpImpl::GetCapture(match_info_array, 1);
2393 }
2394
2395 if (prev < start) {
2396 builder.AddSubjectSlice(prev, start);
2397 }
2398 compiled_replacement.Apply(&builder,
2399 start,
2400 end,
2401 last_match_info_handle);
2402 prev = end;
2403
2404 // Only continue checking for global regexps.
2405 if (!is_global) break;
2406
2407 // Continue from where the match ended, unless it was an empty match.
2408 int next = end;
2409 if (start == end) {
2410 next = end + 1;
2411 if (next > length) break;
2412 }
2413
2414 match = RegExpImpl::Exec(regexp_handle,
2415 subject_handle,
2416 next,
2417 last_match_info_handle);
2418 if (match.is_null()) {
2419 return Failure::Exception();
2420 }
2421 matched = !match->IsNull();
2422 } while (matched);
2423
2424 if (prev < length) {
2425 builder.AddSubjectSlice(prev, length);
2426 }
2427
2428 return *(builder.ToString());
2429}
2430
2431
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002432template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002433MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2434 String* subject,
2435 JSRegExp* regexp,
2436 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002437 ASSERT(subject->IsFlat());
2438
2439 HandleScope handles;
2440
2441 Handle<String> subject_handle(subject);
2442 Handle<JSRegExp> regexp_handle(regexp);
2443 Handle<JSArray> last_match_info_handle(last_match_info);
2444 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2445 subject_handle,
2446 0,
2447 last_match_info_handle);
2448 if (match.is_null()) return Failure::Exception();
2449 if (match->IsNull()) return *subject_handle;
2450
2451 ASSERT(last_match_info_handle->HasFastElements());
2452
2453 HandleScope loop_scope;
2454 int start, end;
2455 {
2456 AssertNoAllocation match_info_array_is_not_in_a_handle;
2457 FixedArray* match_info_array =
2458 FixedArray::cast(last_match_info_handle->elements());
2459
2460 start = RegExpImpl::GetCapture(match_info_array, 0);
2461 end = RegExpImpl::GetCapture(match_info_array, 1);
2462 }
2463
2464 int length = subject->length();
2465 int new_length = length - (end - start);
2466 if (new_length == 0) {
2467 return Heap::empty_string();
2468 }
2469 Handle<ResultSeqString> answer;
2470 if (ResultSeqString::kHasAsciiEncoding) {
2471 answer =
2472 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2473 } else {
2474 answer =
2475 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2476 }
2477
2478 // If the regexp isn't global, only match once.
2479 if (!regexp_handle->GetFlags().is_global()) {
2480 if (start > 0) {
2481 String::WriteToFlat(*subject_handle,
2482 answer->GetChars(),
2483 0,
2484 start);
2485 }
2486 if (end < length) {
2487 String::WriteToFlat(*subject_handle,
2488 answer->GetChars() + start,
2489 end,
2490 length);
2491 }
2492 return *answer;
2493 }
2494
2495 int prev = 0; // Index of end of last match.
2496 int next = 0; // Start of next search (prev unless last match was empty).
2497 int position = 0;
2498
2499 do {
2500 if (prev < start) {
2501 // Add substring subject[prev;start] to answer string.
2502 String::WriteToFlat(*subject_handle,
2503 answer->GetChars() + position,
2504 prev,
2505 start);
2506 position += start - prev;
2507 }
2508 prev = end;
2509 next = end;
2510 // Continue from where the match ended, unless it was an empty match.
2511 if (start == end) {
2512 next++;
2513 if (next > length) break;
2514 }
2515 match = RegExpImpl::Exec(regexp_handle,
2516 subject_handle,
2517 next,
2518 last_match_info_handle);
2519 if (match.is_null()) return Failure::Exception();
2520 if (match->IsNull()) break;
2521
2522 ASSERT(last_match_info_handle->HasFastElements());
2523 HandleScope loop_scope;
2524 {
2525 AssertNoAllocation match_info_array_is_not_in_a_handle;
2526 FixedArray* match_info_array =
2527 FixedArray::cast(last_match_info_handle->elements());
2528 start = RegExpImpl::GetCapture(match_info_array, 0);
2529 end = RegExpImpl::GetCapture(match_info_array, 1);
2530 }
2531 } while (true);
2532
2533 if (prev < length) {
2534 // Add substring subject[prev;length] to answer string.
2535 String::WriteToFlat(*subject_handle,
2536 answer->GetChars() + position,
2537 prev,
2538 length);
2539 position += length - prev;
2540 }
2541
2542 if (position == 0) {
2543 return Heap::empty_string();
2544 }
2545
2546 // Shorten string and fill
2547 int string_size = ResultSeqString::SizeFor(position);
2548 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2549 int delta = allocated_string_size - string_size;
2550
2551 answer->set_length(position);
2552 if (delta == 0) return *answer;
2553
2554 Address end_of_string = answer->address() + string_size;
2555 Heap::CreateFillerObjectAt(end_of_string, delta);
2556
2557 return *answer;
2558}
2559
2560
lrn@chromium.org303ada72010-10-27 09:33:13 +00002561static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002562 ASSERT(args.length() == 4);
2563
2564 CONVERT_CHECKED(String, subject, args[0]);
2565 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002566 Object* flat_subject;
2567 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2568 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2569 return maybe_flat_subject;
2570 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002571 }
2572 subject = String::cast(flat_subject);
2573 }
2574
2575 CONVERT_CHECKED(String, replacement, args[2]);
2576 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002577 Object* flat_replacement;
2578 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2579 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2580 return maybe_flat_replacement;
2581 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002582 }
2583 replacement = String::cast(flat_replacement);
2584 }
2585
2586 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2587 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2588
2589 ASSERT(last_match_info->HasFastElements());
2590
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002591 if (replacement->length() == 0) {
2592 if (subject->HasOnlyAsciiChars()) {
2593 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2594 subject, regexp, last_match_info);
2595 } else {
2596 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2597 subject, regexp, last_match_info);
2598 }
2599 }
2600
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002601 return StringReplaceRegExpWithString(subject,
2602 regexp,
2603 replacement,
2604 last_match_info);
2605}
2606
2607
ager@chromium.org7c537e22008-10-16 08:43:32 +00002608// Perform string match of pattern on subject, starting at start index.
2609// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002610// and should check that pat->length() + start_index <= sub->length().
ager@chromium.org7c537e22008-10-16 08:43:32 +00002611int Runtime::StringMatch(Handle<String> sub,
2612 Handle<String> pat,
2613 int start_index) {
2614 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002615 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002616
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002617 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002618 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002619
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002620 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002621 if (start_index + pattern_length > subject_length) return -1;
2622
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002623 if (!sub->IsFlat()) FlattenString(sub);
2624 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002625
ager@chromium.org7c537e22008-10-16 08:43:32 +00002626 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002627 // Extract flattened substrings of cons strings before determining asciiness.
2628 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002629 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002630 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002631 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002632
ager@chromium.org7c537e22008-10-16 08:43:32 +00002633 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002634 if (seq_pat->IsAsciiRepresentation()) {
2635 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2636 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002637 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002638 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002639 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002640 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002641 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2642 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002643 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002644 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002645 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002646}
2647
2648
lrn@chromium.org303ada72010-10-27 09:33:13 +00002649static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002650 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002651 ASSERT(args.length() == 3);
2652
ager@chromium.org7c537e22008-10-16 08:43:32 +00002653 CONVERT_ARG_CHECKED(String, sub, 0);
2654 CONVERT_ARG_CHECKED(String, pat, 1);
2655
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002656 Object* index = args[2];
2657 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002658 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002659
ager@chromium.org870a0b62008-11-04 11:43:05 +00002660 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002661 int position = Runtime::StringMatch(sub, pat, start_index);
2662 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002663}
2664
2665
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002666template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002667static int StringMatchBackwards(Vector<const schar> subject,
2668 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002669 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002670 int pattern_length = pattern.length();
2671 ASSERT(pattern_length >= 1);
2672 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002673
2674 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002675 for (int i = 0; i < pattern_length; i++) {
2676 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002677 if (c > String::kMaxAsciiCharCode) {
2678 return -1;
2679 }
2680 }
2681 }
2682
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002683 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002684 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002685 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002686 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002687 while (j < pattern_length) {
2688 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002689 break;
2690 }
2691 j++;
2692 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002693 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002694 return i;
2695 }
2696 }
2697 return -1;
2698}
2699
lrn@chromium.org303ada72010-10-27 09:33:13 +00002700static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002701 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002702 ASSERT(args.length() == 3);
2703
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002704 CONVERT_ARG_CHECKED(String, sub, 0);
2705 CONVERT_ARG_CHECKED(String, pat, 1);
2706
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002707 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002708 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002709 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002710
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002711 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002712 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002713
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002714 if (start_index + pat_length > sub_length) {
2715 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002716 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002717
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002718 if (pat_length == 0) {
2719 return Smi::FromInt(start_index);
2720 }
2721
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002722 if (!sub->IsFlat()) FlattenString(sub);
2723 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002724
2725 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2726
2727 int position = -1;
2728
2729 if (pat->IsAsciiRepresentation()) {
2730 Vector<const char> pat_vector = pat->ToAsciiVector();
2731 if (sub->IsAsciiRepresentation()) {
2732 position = StringMatchBackwards(sub->ToAsciiVector(),
2733 pat_vector,
2734 start_index);
2735 } else {
2736 position = StringMatchBackwards(sub->ToUC16Vector(),
2737 pat_vector,
2738 start_index);
2739 }
2740 } else {
2741 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2742 if (sub->IsAsciiRepresentation()) {
2743 position = StringMatchBackwards(sub->ToAsciiVector(),
2744 pat_vector,
2745 start_index);
2746 } else {
2747 position = StringMatchBackwards(sub->ToUC16Vector(),
2748 pat_vector,
2749 start_index);
2750 }
2751 }
2752
2753 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002754}
2755
2756
lrn@chromium.org303ada72010-10-27 09:33:13 +00002757static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002758 NoHandleAllocation ha;
2759 ASSERT(args.length() == 2);
2760
2761 CONVERT_CHECKED(String, str1, args[0]);
2762 CONVERT_CHECKED(String, str2, args[1]);
2763
2764 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002765 int str1_length = str1->length();
2766 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002767
2768 // Decide trivial cases without flattening.
2769 if (str1_length == 0) {
2770 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2771 return Smi::FromInt(-str2_length);
2772 } else {
2773 if (str2_length == 0) return Smi::FromInt(str1_length);
2774 }
2775
2776 int end = str1_length < str2_length ? str1_length : str2_length;
2777
2778 // No need to flatten if we are going to find the answer on the first
2779 // character. At this point we know there is at least one character
2780 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002781 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002782 if (d != 0) return Smi::FromInt(d);
2783
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002784 str1->TryFlatten();
2785 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002786
2787 static StringInputBuffer buf1;
2788 static StringInputBuffer buf2;
2789
2790 buf1.Reset(str1);
2791 buf2.Reset(str2);
2792
2793 for (int i = 0; i < end; i++) {
2794 uint16_t char1 = buf1.GetNext();
2795 uint16_t char2 = buf2.GetNext();
2796 if (char1 != char2) return Smi::FromInt(char1 - char2);
2797 }
2798
2799 return Smi::FromInt(str1_length - str2_length);
2800}
2801
2802
lrn@chromium.org303ada72010-10-27 09:33:13 +00002803static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002804 NoHandleAllocation ha;
2805 ASSERT(args.length() == 3);
2806
2807 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002808 Object* from = args[1];
2809 Object* to = args[2];
2810 int start, end;
2811 // We have a fast integer-only case here to avoid a conversion to double in
2812 // the common case where from and to are Smis.
2813 if (from->IsSmi() && to->IsSmi()) {
2814 start = Smi::cast(from)->value();
2815 end = Smi::cast(to)->value();
2816 } else {
2817 CONVERT_DOUBLE_CHECKED(from_number, from);
2818 CONVERT_DOUBLE_CHECKED(to_number, to);
2819 start = FastD2I(from_number);
2820 end = FastD2I(to_number);
2821 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002822 RUNTIME_ASSERT(end >= start);
2823 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002824 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002825 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002826 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002827}
2828
2829
lrn@chromium.org303ada72010-10-27 09:33:13 +00002830static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002831 ASSERT_EQ(3, args.length());
2832
2833 CONVERT_ARG_CHECKED(String, subject, 0);
2834 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2835 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2836 HandleScope handles;
2837
2838 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2839
2840 if (match.is_null()) {
2841 return Failure::Exception();
2842 }
2843 if (match->IsNull()) {
2844 return Heap::null_value();
2845 }
2846 int length = subject->length();
2847
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002848 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002849 ZoneList<int> offsets(8);
2850 do {
2851 int start;
2852 int end;
2853 {
2854 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002855 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002856 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2857 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2858 }
2859 offsets.Add(start);
2860 offsets.Add(end);
2861 int index = start < end ? end : end + 1;
2862 if (index > length) break;
2863 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2864 if (match.is_null()) {
2865 return Failure::Exception();
2866 }
2867 } while (!match->IsNull());
2868 int matches = offsets.length() / 2;
2869 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2870 for (int i = 0; i < matches ; i++) {
2871 int from = offsets.at(i * 2);
2872 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002873 Handle<String> match = Factory::NewSubString(subject, from, to);
2874 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00002875 }
2876 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2877 result->set_length(Smi::FromInt(matches));
2878 return *result;
2879}
2880
2881
lrn@chromium.org25156de2010-04-06 13:10:27 +00002882// Two smis before and after the match, for very long strings.
2883const int kMaxBuilderEntriesPerRegExpMatch = 5;
2884
2885
2886static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2887 Handle<JSArray> last_match_info,
2888 int match_start,
2889 int match_end) {
2890 // Fill last_match_info with a single capture.
2891 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2892 AssertNoAllocation no_gc;
2893 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2894 RegExpImpl::SetLastCaptureCount(elements, 2);
2895 RegExpImpl::SetLastInput(elements, *subject);
2896 RegExpImpl::SetLastSubject(elements, *subject);
2897 RegExpImpl::SetCapture(elements, 0, match_start);
2898 RegExpImpl::SetCapture(elements, 1, match_end);
2899}
2900
2901
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002902template <typename SubjectChar, typename PatternChar>
2903static bool SearchStringMultiple(Vector<const SubjectChar> subject,
2904 Vector<const PatternChar> pattern,
2905 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002906 FixedArrayBuilder* builder,
2907 int* match_pos) {
2908 int pos = *match_pos;
2909 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002910 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002911 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002912 StringSearch<PatternChar, SubjectChar> search(pattern);
2913 while (pos <= max_search_start) {
2914 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
2915 *match_pos = pos;
2916 return false;
2917 }
2918 // Position of end of previous match.
2919 int match_end = pos + pattern_length;
2920 int new_pos = search.Search(subject, match_end);
2921 if (new_pos >= 0) {
2922 // A match.
2923 if (new_pos > match_end) {
2924 ReplacementStringBuilder::AddSubjectSlice(builder,
2925 match_end,
2926 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002927 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002928 pos = new_pos;
2929 builder->Add(pattern_string);
2930 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002931 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002932 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002933 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002934
lrn@chromium.org25156de2010-04-06 13:10:27 +00002935 if (pos < max_search_start) {
2936 ReplacementStringBuilder::AddSubjectSlice(builder,
2937 pos + pattern_length,
2938 subject_length);
2939 }
2940 *match_pos = pos;
2941 return true;
2942}
2943
2944
2945static bool SearchStringMultiple(Handle<String> subject,
2946 Handle<String> pattern,
2947 Handle<JSArray> last_match_info,
2948 FixedArrayBuilder* builder) {
2949 ASSERT(subject->IsFlat());
2950 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002951
2952 // Treating as if a previous match was before first character.
2953 int match_pos = -pattern->length();
2954
2955 for (;;) { // Break when search complete.
2956 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
2957 AssertNoAllocation no_gc;
2958 if (subject->IsAsciiRepresentation()) {
2959 Vector<const char> subject_vector = subject->ToAsciiVector();
2960 if (pattern->IsAsciiRepresentation()) {
2961 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002962 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002963 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002964 builder,
2965 &match_pos)) break;
2966 } else {
2967 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002968 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002969 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002970 builder,
2971 &match_pos)) break;
2972 }
2973 } else {
2974 Vector<const uc16> subject_vector = subject->ToUC16Vector();
2975 if (pattern->IsAsciiRepresentation()) {
2976 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002977 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002978 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002979 builder,
2980 &match_pos)) break;
2981 } else {
2982 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002983 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002984 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002985 builder,
2986 &match_pos)) break;
2987 }
2988 }
2989 }
2990
2991 if (match_pos >= 0) {
2992 SetLastMatchInfoNoCaptures(subject,
2993 last_match_info,
2994 match_pos,
2995 match_pos + pattern->length());
2996 return true;
2997 }
2998 return false; // No matches at all.
2999}
3000
3001
3002static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3003 Handle<String> subject,
3004 Handle<JSRegExp> regexp,
3005 Handle<JSArray> last_match_array,
3006 FixedArrayBuilder* builder) {
3007 ASSERT(subject->IsFlat());
3008 int match_start = -1;
3009 int match_end = 0;
3010 int pos = 0;
3011 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3012 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3013
3014 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003015 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003016 int subject_length = subject->length();
3017
3018 for (;;) { // Break on failure, return on exception.
3019 RegExpImpl::IrregexpResult result =
3020 RegExpImpl::IrregexpExecOnce(regexp,
3021 subject,
3022 pos,
3023 register_vector);
3024 if (result == RegExpImpl::RE_SUCCESS) {
3025 match_start = register_vector[0];
3026 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3027 if (match_end < match_start) {
3028 ReplacementStringBuilder::AddSubjectSlice(builder,
3029 match_end,
3030 match_start);
3031 }
3032 match_end = register_vector[1];
3033 HandleScope loop_scope;
3034 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3035 if (match_start != match_end) {
3036 pos = match_end;
3037 } else {
3038 pos = match_end + 1;
3039 if (pos > subject_length) break;
3040 }
3041 } else if (result == RegExpImpl::RE_FAILURE) {
3042 break;
3043 } else {
3044 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3045 return result;
3046 }
3047 }
3048
3049 if (match_start >= 0) {
3050 if (match_end < subject_length) {
3051 ReplacementStringBuilder::AddSubjectSlice(builder,
3052 match_end,
3053 subject_length);
3054 }
3055 SetLastMatchInfoNoCaptures(subject,
3056 last_match_array,
3057 match_start,
3058 match_end);
3059 return RegExpImpl::RE_SUCCESS;
3060 } else {
3061 return RegExpImpl::RE_FAILURE; // No matches at all.
3062 }
3063}
3064
3065
3066static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3067 Handle<String> subject,
3068 Handle<JSRegExp> regexp,
3069 Handle<JSArray> last_match_array,
3070 FixedArrayBuilder* builder) {
3071
3072 ASSERT(subject->IsFlat());
3073 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3074 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3075
3076 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003077 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003078
3079 RegExpImpl::IrregexpResult result =
3080 RegExpImpl::IrregexpExecOnce(regexp,
3081 subject,
3082 0,
3083 register_vector);
3084
3085 int capture_count = regexp->CaptureCount();
3086 int subject_length = subject->length();
3087
3088 // Position to search from.
3089 int pos = 0;
3090 // End of previous match. Differs from pos if match was empty.
3091 int match_end = 0;
3092 if (result == RegExpImpl::RE_SUCCESS) {
3093 // Need to keep a copy of the previous match for creating last_match_info
3094 // at the end, so we have two vectors that we swap between.
3095 OffsetsVector registers2(required_registers);
3096 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3097
3098 do {
3099 int match_start = register_vector[0];
3100 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3101 if (match_end < match_start) {
3102 ReplacementStringBuilder::AddSubjectSlice(builder,
3103 match_end,
3104 match_start);
3105 }
3106 match_end = register_vector[1];
3107
3108 {
3109 // Avoid accumulating new handles inside loop.
3110 HandleScope temp_scope;
3111 // Arguments array to replace function is match, captures, index and
3112 // subject, i.e., 3 + capture count in total.
3113 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003114 Handle<String> match = Factory::NewSubString(subject,
3115 match_start,
3116 match_end);
3117 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003118 for (int i = 1; i <= capture_count; i++) {
3119 int start = register_vector[i * 2];
3120 if (start >= 0) {
3121 int end = register_vector[i * 2 + 1];
3122 ASSERT(start <= end);
3123 Handle<String> substring = Factory::NewSubString(subject,
3124 start,
3125 end);
3126 elements->set(i, *substring);
3127 } else {
3128 ASSERT(register_vector[i * 2 + 1] < 0);
3129 elements->set(i, Heap::undefined_value());
3130 }
3131 }
3132 elements->set(capture_count + 1, Smi::FromInt(match_start));
3133 elements->set(capture_count + 2, *subject);
3134 builder->Add(*Factory::NewJSArrayWithElements(elements));
3135 }
3136 // Swap register vectors, so the last successful match is in
3137 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003138 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003139 prev_register_vector = register_vector;
3140 register_vector = tmp;
3141
3142 if (match_end > match_start) {
3143 pos = match_end;
3144 } else {
3145 pos = match_end + 1;
3146 if (pos > subject_length) {
3147 break;
3148 }
3149 }
3150
3151 result = RegExpImpl::IrregexpExecOnce(regexp,
3152 subject,
3153 pos,
3154 register_vector);
3155 } while (result == RegExpImpl::RE_SUCCESS);
3156
3157 if (result != RegExpImpl::RE_EXCEPTION) {
3158 // Finished matching, with at least one match.
3159 if (match_end < subject_length) {
3160 ReplacementStringBuilder::AddSubjectSlice(builder,
3161 match_end,
3162 subject_length);
3163 }
3164
3165 int last_match_capture_count = (capture_count + 1) * 2;
3166 int last_match_array_size =
3167 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3168 last_match_array->EnsureSize(last_match_array_size);
3169 AssertNoAllocation no_gc;
3170 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3171 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3172 RegExpImpl::SetLastSubject(elements, *subject);
3173 RegExpImpl::SetLastInput(elements, *subject);
3174 for (int i = 0; i < last_match_capture_count; i++) {
3175 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3176 }
3177 return RegExpImpl::RE_SUCCESS;
3178 }
3179 }
3180 // No matches at all, return failure or exception result directly.
3181 return result;
3182}
3183
3184
lrn@chromium.org303ada72010-10-27 09:33:13 +00003185static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003186 ASSERT(args.length() == 4);
3187 HandleScope handles;
3188
3189 CONVERT_ARG_CHECKED(String, subject, 1);
3190 if (!subject->IsFlat()) { FlattenString(subject); }
3191 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3192 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3193 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3194
3195 ASSERT(last_match_info->HasFastElements());
3196 ASSERT(regexp->GetFlags().is_global());
3197 Handle<FixedArray> result_elements;
3198 if (result_array->HasFastElements()) {
3199 result_elements =
3200 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3201 } else {
3202 result_elements = Factory::NewFixedArrayWithHoles(16);
3203 }
3204 FixedArrayBuilder builder(result_elements);
3205
3206 if (regexp->TypeTag() == JSRegExp::ATOM) {
3207 Handle<String> pattern(
3208 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003209 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003210 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3211 return *builder.ToJSArray(result_array);
3212 }
3213 return Heap::null_value();
3214 }
3215
3216 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3217
3218 RegExpImpl::IrregexpResult result;
3219 if (regexp->CaptureCount() == 0) {
3220 result = SearchRegExpNoCaptureMultiple(subject,
3221 regexp,
3222 last_match_info,
3223 &builder);
3224 } else {
3225 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3226 }
3227 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3228 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3229 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3230 return Failure::Exception();
3231}
3232
3233
lrn@chromium.org303ada72010-10-27 09:33:13 +00003234static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003235 NoHandleAllocation ha;
3236 ASSERT(args.length() == 2);
3237
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003238 // Fast case where the result is a one character string.
3239 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3240 int value = Smi::cast(args[0])->value();
3241 int radix = Smi::cast(args[1])->value();
3242 if (value >= 0 && value < radix) {
3243 RUNTIME_ASSERT(radix <= 36);
3244 // Character array used for conversion.
3245 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3246 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3247 }
3248 }
3249
3250 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003251 CONVERT_DOUBLE_CHECKED(value, args[0]);
3252 if (isnan(value)) {
3253 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3254 }
3255 if (isinf(value)) {
3256 if (value < 0) {
3257 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3258 }
3259 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3260 }
3261 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3262 int radix = FastD2I(radix_number);
3263 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3264 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003265 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003266 DeleteArray(str);
3267 return result;
3268}
3269
3270
lrn@chromium.org303ada72010-10-27 09:33:13 +00003271static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003272 NoHandleAllocation ha;
3273 ASSERT(args.length() == 2);
3274
3275 CONVERT_DOUBLE_CHECKED(value, args[0]);
3276 if (isnan(value)) {
3277 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3278 }
3279 if (isinf(value)) {
3280 if (value < 0) {
3281 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3282 }
3283 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3284 }
3285 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3286 int f = FastD2I(f_number);
3287 RUNTIME_ASSERT(f >= 0);
3288 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003289 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003290 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003291 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003292}
3293
3294
lrn@chromium.org303ada72010-10-27 09:33:13 +00003295static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003296 NoHandleAllocation ha;
3297 ASSERT(args.length() == 2);
3298
3299 CONVERT_DOUBLE_CHECKED(value, args[0]);
3300 if (isnan(value)) {
3301 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3302 }
3303 if (isinf(value)) {
3304 if (value < 0) {
3305 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3306 }
3307 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3308 }
3309 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3310 int f = FastD2I(f_number);
3311 RUNTIME_ASSERT(f >= -1 && f <= 20);
3312 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003313 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003314 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003315 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003316}
3317
3318
lrn@chromium.org303ada72010-10-27 09:33:13 +00003319static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003320 NoHandleAllocation ha;
3321 ASSERT(args.length() == 2);
3322
3323 CONVERT_DOUBLE_CHECKED(value, args[0]);
3324 if (isnan(value)) {
3325 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3326 }
3327 if (isinf(value)) {
3328 if (value < 0) {
3329 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3330 }
3331 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3332 }
3333 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3334 int f = FastD2I(f_number);
3335 RUNTIME_ASSERT(f >= 1 && f <= 21);
3336 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003337 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003338 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003339 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003340}
3341
3342
3343// Returns a single character string where first character equals
3344// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003345static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003346 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003347 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003348 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003349 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003350 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003351 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003352}
3353
3354
lrn@chromium.org303ada72010-10-27 09:33:13 +00003355MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3356 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003357 // Handle [] indexing on Strings
3358 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003359 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3360 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003361 }
3362
3363 // Handle [] indexing on String objects
3364 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003365 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3366 Handle<Object> result =
3367 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3368 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003369 }
3370
3371 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003372 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003373 return prototype->GetElement(index);
3374 }
3375
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003376 return GetElement(object, index);
3377}
3378
3379
lrn@chromium.org303ada72010-10-27 09:33:13 +00003380MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003381 return object->GetElement(index);
3382}
3383
3384
lrn@chromium.org303ada72010-10-27 09:33:13 +00003385MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3386 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003387 HandleScope scope;
3388
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003389 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003390 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003391 Handle<Object> error =
3392 Factory::NewTypeError("non_object_property_load",
3393 HandleVector(args, 2));
3394 return Top::Throw(*error);
3395 }
3396
3397 // Check if the given key is an array index.
3398 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003399 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003400 return GetElementOrCharAt(object, index);
3401 }
3402
3403 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003404 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003405 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003406 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003407 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003408 bool has_pending_exception = false;
3409 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003410 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003411 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003412 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003413 }
3414
ager@chromium.org32912102009-01-16 10:38:43 +00003415 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003416 // the element if so.
3417 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003418 return GetElementOrCharAt(object, index);
3419 } else {
3420 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003421 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003422 }
3423}
3424
3425
lrn@chromium.org303ada72010-10-27 09:33:13 +00003426static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003427 NoHandleAllocation ha;
3428 ASSERT(args.length() == 2);
3429
3430 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003431 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003432
3433 return Runtime::GetObjectProperty(object, key);
3434}
3435
3436
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003437// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003438static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003439 NoHandleAllocation ha;
3440 ASSERT(args.length() == 2);
3441
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003442 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003443 // itself.
3444 //
3445 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003446 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003447 // global proxy object never has properties. This is the case
3448 // because the global proxy object forwards everything to its hidden
3449 // prototype including local lookups.
3450 //
3451 // Additionally, we need to make sure that we do not cache results
3452 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003453 if (args[0]->IsJSObject() &&
3454 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003455 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003456 args[1]->IsString()) {
3457 JSObject* receiver = JSObject::cast(args[0]);
3458 String* key = String::cast(args[1]);
3459 if (receiver->HasFastProperties()) {
3460 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003461 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003462 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3463 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003464 Object* value = receiver->FastPropertyAt(offset);
3465 return value->IsTheHole() ? Heap::undefined_value() : value;
3466 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003467 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003468 LookupResult result;
3469 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003470 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003471 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003472 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003473 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003474 }
3475 } else {
3476 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003477 StringDictionary* dictionary = receiver->property_dictionary();
3478 int entry = dictionary->FindEntry(key);
3479 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003480 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003481 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003482 if (!receiver->IsGlobalObject()) return value;
3483 value = JSGlobalPropertyCell::cast(value)->value();
3484 if (!value->IsTheHole()) return value;
3485 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003486 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003487 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003488 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3489 // Fast case for string indexing using [] with a smi index.
3490 HandleScope scope;
3491 Handle<String> str = args.at<String>(0);
3492 int index = Smi::cast(args[1])->value();
3493 Handle<Object> result = GetCharAt(str, index);
3494 return *result;
ager@chromium.org7c537e22008-10-16 08:43:32 +00003495 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003496
3497 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003498 return Runtime::GetObjectProperty(args.at<Object>(0),
3499 args.at<Object>(1));
3500}
3501
3502
lrn@chromium.org303ada72010-10-27 09:33:13 +00003503static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003504 ASSERT(args.length() == 5);
3505 HandleScope scope;
3506 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3507 CONVERT_CHECKED(String, name, args[1]);
3508 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003509 Object* fun = args[3];
3510 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003511 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3512 int unchecked = flag_attr->value();
3513 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3514 RUNTIME_ASSERT(!obj->IsNull());
3515 LookupResult result;
3516 obj->LocalLookupRealNamedProperty(name, &result);
3517
3518 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3519 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3520 // delete it to avoid running into trouble in DefineAccessor, which
3521 // handles this incorrectly if the property is readonly (does nothing)
3522 if (result.IsProperty() &&
3523 (result.type() == FIELD || result.type() == NORMAL
3524 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003525 Object* ok;
3526 { MaybeObject* maybe_ok =
3527 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3528 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3529 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003530 }
3531 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3532}
3533
lrn@chromium.org303ada72010-10-27 09:33:13 +00003534static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003535 ASSERT(args.length() == 4);
3536 HandleScope scope;
3537 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3538 CONVERT_ARG_CHECKED(String, name, 1);
3539 Handle<Object> obj_value = args.at<Object>(2);
3540
3541 CONVERT_CHECKED(Smi, flag, args[3]);
3542 int unchecked = flag->value();
3543 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3544
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003545 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3546
3547 // Check if this is an element.
3548 uint32_t index;
3549 bool is_element = name->AsArrayIndex(&index);
3550
3551 // Special case for elements if any of the flags are true.
3552 // If elements are in fast case we always implicitly assume that:
3553 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3554 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3555 is_element) {
3556 // Normalize the elements to enable attributes on the property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003557 NormalizeElements(js_object);
3558 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003559 // Make sure that we never go back to fast case.
3560 dictionary->set_requires_slow_elements();
3561 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003562 NumberDictionarySet(dictionary, index, obj_value, details);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003563 }
3564
ager@chromium.org5c838252010-02-19 08:53:10 +00003565 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003566 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003567
ager@chromium.org5c838252010-02-19 08:53:10 +00003568 // Take special care when attributes are different and there is already
3569 // a property. For simplicity we normalize the property which enables us
3570 // to not worry about changing the instance_descriptor and creating a new
3571 // map. The current version of SetObjectProperty does not handle attributes
3572 // correctly in the case where a property is a field and is reset with
3573 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003574 if (result.IsProperty() &&
3575 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003576 // New attributes - normalize to avoid writing to instance descriptor
lrn@chromium.org303ada72010-10-27 09:33:13 +00003577 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003578 // Use IgnoreAttributes version since a readonly property may be
3579 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003580 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3581 *obj_value,
3582 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003583 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003584
ager@chromium.org5c838252010-02-19 08:53:10 +00003585 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3586}
3587
3588
lrn@chromium.org303ada72010-10-27 09:33:13 +00003589MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3590 Handle<Object> key,
3591 Handle<Object> value,
3592 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003593 HandleScope scope;
3594
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003596 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003597 Handle<Object> error =
3598 Factory::NewTypeError("non_object_property_store",
3599 HandleVector(args, 2));
3600 return Top::Throw(*error);
3601 }
3602
3603 // If the object isn't a JavaScript object, we ignore the store.
3604 if (!object->IsJSObject()) return *value;
3605
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003606 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3607
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003608 // Check if the given key is an array index.
3609 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003610 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003611 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3612 // of a string using [] notation. We need to support this too in
3613 // JavaScript.
3614 // In the case of a String object we just need to redirect the assignment to
3615 // the underlying string if the index is in range. Since the underlying
3616 // string does nothing with the assignment then we can ignore such
3617 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003618 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003619 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003620 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003621
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003622 Handle<Object> result = SetElement(js_object, index, value);
3623 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003624 return *value;
3625 }
3626
3627 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003628 Handle<Object> result;
3629 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003630 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003631 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003632 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003633 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003634 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003635 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003636 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003637 return *value;
3638 }
3639
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003640 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003641 bool has_pending_exception = false;
3642 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3643 if (has_pending_exception) return Failure::Exception();
3644 Handle<String> name = Handle<String>::cast(converted);
3645
3646 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003647 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003648 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003649 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003650 }
3651}
3652
3653
lrn@chromium.org303ada72010-10-27 09:33:13 +00003654MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3655 Handle<Object> key,
3656 Handle<Object> value,
3657 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003658 HandleScope scope;
3659
3660 // Check if the given key is an array index.
3661 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003662 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003663 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3664 // of a string using [] notation. We need to support this too in
3665 // JavaScript.
3666 // In the case of a String object we just need to redirect the assignment to
3667 // the underlying string if the index is in range. Since the underlying
3668 // string does nothing with the assignment then we can ignore such
3669 // assignments.
3670 if (js_object->IsStringObjectWithCharacterAt(index)) {
3671 return *value;
3672 }
3673
3674 return js_object->SetElement(index, *value);
3675 }
3676
3677 if (key->IsString()) {
3678 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003679 return js_object->SetElement(index, *value);
3680 } else {
3681 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003682 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003683 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
3684 *value,
3685 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003686 }
3687 }
3688
3689 // Call-back into JavaScript to convert the key to a string.
3690 bool has_pending_exception = false;
3691 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3692 if (has_pending_exception) return Failure::Exception();
3693 Handle<String> name = Handle<String>::cast(converted);
3694
3695 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003696 return js_object->SetElement(index, *value);
3697 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003698 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003699 }
3700}
3701
3702
lrn@chromium.org303ada72010-10-27 09:33:13 +00003703MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3704 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003705 HandleScope scope;
3706
3707 // Check if the given key is an array index.
3708 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003709 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003710 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3711 // characters of a string using [] notation. In the case of a
3712 // String object we just need to redirect the deletion to the
3713 // underlying string if the index is in range. Since the
3714 // underlying string does nothing with the deletion, we can ignore
3715 // such deletions.
3716 if (js_object->IsStringObjectWithCharacterAt(index)) {
3717 return Heap::true_value();
3718 }
3719
3720 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3721 }
3722
3723 Handle<String> key_string;
3724 if (key->IsString()) {
3725 key_string = Handle<String>::cast(key);
3726 } else {
3727 // Call-back into JavaScript to convert the key to a string.
3728 bool has_pending_exception = false;
3729 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3730 if (has_pending_exception) return Failure::Exception();
3731 key_string = Handle<String>::cast(converted);
3732 }
3733
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003734 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003735 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3736}
3737
3738
lrn@chromium.org303ada72010-10-27 09:33:13 +00003739static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003740 NoHandleAllocation ha;
3741 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3742
3743 Handle<Object> object = args.at<Object>(0);
3744 Handle<Object> key = args.at<Object>(1);
3745 Handle<Object> value = args.at<Object>(2);
3746
3747 // Compute attributes.
3748 PropertyAttributes attributes = NONE;
3749 if (args.length() == 4) {
3750 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003751 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003752 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003753 RUNTIME_ASSERT(
3754 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3755 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003756 }
3757 return Runtime::SetObjectProperty(object, key, value, attributes);
3758}
3759
3760
3761// Set a local property, even if it is READ_ONLY. If the property does not
3762// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003763static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003764 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003765 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003766 CONVERT_CHECKED(JSObject, object, args[0]);
3767 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003768 // Compute attributes.
3769 PropertyAttributes attributes = NONE;
3770 if (args.length() == 4) {
3771 CONVERT_CHECKED(Smi, value_obj, args[3]);
3772 int unchecked_value = value_obj->value();
3773 // Only attribute bits should be set.
3774 RUNTIME_ASSERT(
3775 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3776 attributes = static_cast<PropertyAttributes>(unchecked_value);
3777 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003778
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003779 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003780 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003781}
3782
3783
lrn@chromium.org303ada72010-10-27 09:33:13 +00003784static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003785 NoHandleAllocation ha;
3786 ASSERT(args.length() == 2);
3787
3788 CONVERT_CHECKED(JSObject, object, args[0]);
3789 CONVERT_CHECKED(String, key, args[1]);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003790 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003791}
3792
3793
ager@chromium.org9085a012009-05-11 19:22:57 +00003794static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3795 Handle<String> key) {
3796 if (object->HasLocalProperty(*key)) return Heap::true_value();
3797 // Handle hidden prototypes. If there's a hidden prototype above this thing
3798 // then we have to check it for properties, because they are supposed to
3799 // look like they are on this object.
3800 Handle<Object> proto(object->GetPrototype());
3801 if (proto->IsJSObject() &&
3802 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3803 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3804 }
3805 return Heap::false_value();
3806}
3807
3808
lrn@chromium.org303ada72010-10-27 09:33:13 +00003809static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003810 NoHandleAllocation ha;
3811 ASSERT(args.length() == 2);
3812 CONVERT_CHECKED(String, key, args[1]);
3813
ager@chromium.org9085a012009-05-11 19:22:57 +00003814 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003815 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003816 if (obj->IsJSObject()) {
3817 JSObject* object = JSObject::cast(obj);
3818 // Fast case - no interceptors.
3819 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3820 // Slow case. Either it's not there or we have an interceptor. We should
3821 // have handles for this kind of deal.
3822 HandleScope scope;
3823 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3824 Handle<String>(key));
3825 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003826 // Well, there is one exception: Handle [] on strings.
3827 uint32_t index;
3828 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003829 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003830 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003831 return Heap::true_value();
3832 }
3833 }
3834 return Heap::false_value();
3835}
3836
3837
lrn@chromium.org303ada72010-10-27 09:33:13 +00003838static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003839 NoHandleAllocation na;
3840 ASSERT(args.length() == 2);
3841
3842 // Only JS objects can have properties.
3843 if (args[0]->IsJSObject()) {
3844 JSObject* object = JSObject::cast(args[0]);
3845 CONVERT_CHECKED(String, key, args[1]);
3846 if (object->HasProperty(key)) return Heap::true_value();
3847 }
3848 return Heap::false_value();
3849}
3850
3851
lrn@chromium.org303ada72010-10-27 09:33:13 +00003852static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003853 NoHandleAllocation na;
3854 ASSERT(args.length() == 2);
3855
3856 // Only JS objects can have elements.
3857 if (args[0]->IsJSObject()) {
3858 JSObject* object = JSObject::cast(args[0]);
3859 CONVERT_CHECKED(Smi, index_obj, args[1]);
3860 uint32_t index = index_obj->value();
3861 if (object->HasElement(index)) return Heap::true_value();
3862 }
3863 return Heap::false_value();
3864}
3865
3866
lrn@chromium.org303ada72010-10-27 09:33:13 +00003867static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003868 NoHandleAllocation ha;
3869 ASSERT(args.length() == 2);
3870
3871 CONVERT_CHECKED(JSObject, object, args[0]);
3872 CONVERT_CHECKED(String, key, args[1]);
3873
3874 uint32_t index;
3875 if (key->AsArrayIndex(&index)) {
3876 return Heap::ToBoolean(object->HasElement(index));
3877 }
3878
ager@chromium.org870a0b62008-11-04 11:43:05 +00003879 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
3880 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003881}
3882
3883
lrn@chromium.org303ada72010-10-27 09:33:13 +00003884static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003885 HandleScope scope;
3886 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003887 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003888 return *GetKeysFor(object);
3889}
3890
3891
3892// Returns either a FixedArray as Runtime_GetPropertyNames,
3893// or, if the given object has an enum cache that contains
3894// all enumerable properties of the object and its prototypes
3895// have none, the map of the object. This is used to speed up
3896// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003897static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003898 ASSERT(args.length() == 1);
3899
3900 CONVERT_CHECKED(JSObject, raw_object, args[0]);
3901
3902 if (raw_object->IsSimpleEnum()) return raw_object->map();
3903
3904 HandleScope scope;
3905 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00003906 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
3907 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003908
3909 // Test again, since cache may have been built by preceding call.
3910 if (object->IsSimpleEnum()) return object->map();
3911
3912 return *content;
3913}
3914
3915
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003916// Find the length of the prototype chain that is to to handled as one. If a
3917// prototype object is hidden it is to be viewed as part of the the object it
3918// is prototype for.
3919static int LocalPrototypeChainLength(JSObject* obj) {
3920 int count = 1;
3921 Object* proto = obj->GetPrototype();
3922 while (proto->IsJSObject() &&
3923 JSObject::cast(proto)->map()->is_hidden_prototype()) {
3924 count++;
3925 proto = JSObject::cast(proto)->GetPrototype();
3926 }
3927 return count;
3928}
3929
3930
3931// Return the names of the local named properties.
3932// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00003933static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003934 HandleScope scope;
3935 ASSERT(args.length() == 1);
3936 if (!args[0]->IsJSObject()) {
3937 return Heap::undefined_value();
3938 }
3939 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3940
3941 // Skip the global proxy as it has no properties and always delegates to the
3942 // real global object.
3943 if (obj->IsJSGlobalProxy()) {
3944 // Only collect names if access is permitted.
3945 if (obj->IsAccessCheckNeeded() &&
3946 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
3947 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
3948 return *Factory::NewJSArray(0);
3949 }
3950 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
3951 }
3952
3953 // Find the number of objects making up this.
3954 int length = LocalPrototypeChainLength(*obj);
3955
3956 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003957 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003958 int total_property_count = 0;
3959 Handle<JSObject> jsproto = obj;
3960 for (int i = 0; i < length; i++) {
3961 // Only collect names if access is permitted.
3962 if (jsproto->IsAccessCheckNeeded() &&
3963 !Top::MayNamedAccess(*jsproto,
3964 Heap::undefined_value(),
3965 v8::ACCESS_KEYS)) {
3966 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
3967 return *Factory::NewJSArray(0);
3968 }
3969 int n;
3970 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
3971 local_property_count[i] = n;
3972 total_property_count += n;
3973 if (i < length - 1) {
3974 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3975 }
3976 }
3977
3978 // Allocate an array with storage for all the property names.
3979 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
3980
3981 // Get the property names.
3982 jsproto = obj;
3983 int proto_with_hidden_properties = 0;
3984 for (int i = 0; i < length; i++) {
3985 jsproto->GetLocalPropertyNames(*names,
3986 i == 0 ? 0 : local_property_count[i - 1]);
3987 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
3988 proto_with_hidden_properties++;
3989 }
3990 if (i < length - 1) {
3991 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3992 }
3993 }
3994
3995 // Filter out name of hidden propeties object.
3996 if (proto_with_hidden_properties > 0) {
3997 Handle<FixedArray> old_names = names;
3998 names = Factory::NewFixedArray(
3999 names->length() - proto_with_hidden_properties);
4000 int dest_pos = 0;
4001 for (int i = 0; i < total_property_count; i++) {
4002 Object* name = old_names->get(i);
4003 if (name == Heap::hidden_symbol()) {
4004 continue;
4005 }
4006 names->set(dest_pos++, name);
4007 }
4008 }
4009
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004010 return *Factory::NewJSArrayWithElements(names);
4011}
4012
4013
4014// Return the names of the local indexed properties.
4015// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004016static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004017 HandleScope scope;
4018 ASSERT(args.length() == 1);
4019 if (!args[0]->IsJSObject()) {
4020 return Heap::undefined_value();
4021 }
4022 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4023
4024 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4025 Handle<FixedArray> names = Factory::NewFixedArray(n);
4026 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4027 return *Factory::NewJSArrayWithElements(names);
4028}
4029
4030
4031// Return information on whether an object has a named or indexed interceptor.
4032// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004033static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004034 HandleScope scope;
4035 ASSERT(args.length() == 1);
4036 if (!args[0]->IsJSObject()) {
4037 return Smi::FromInt(0);
4038 }
4039 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4040
4041 int result = 0;
4042 if (obj->HasNamedInterceptor()) result |= 2;
4043 if (obj->HasIndexedInterceptor()) result |= 1;
4044
4045 return Smi::FromInt(result);
4046}
4047
4048
4049// Return property names from named interceptor.
4050// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004051static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004052 HandleScope scope;
4053 ASSERT(args.length() == 1);
4054 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4055
4056 if (obj->HasNamedInterceptor()) {
4057 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4058 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4059 }
4060 return Heap::undefined_value();
4061}
4062
4063
4064// Return element names from indexed interceptor.
4065// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004066static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004067 HandleScope scope;
4068 ASSERT(args.length() == 1);
4069 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4070
4071 if (obj->HasIndexedInterceptor()) {
4072 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4073 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4074 }
4075 return Heap::undefined_value();
4076}
4077
4078
lrn@chromium.org303ada72010-10-27 09:33:13 +00004079static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004080 ASSERT_EQ(args.length(), 1);
4081 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4082 HandleScope scope;
4083 Handle<JSObject> object(raw_object);
4084 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4085 LOCAL_ONLY);
4086 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4087 // property array and since the result is mutable we have to create
4088 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004089 int length = contents->length();
4090 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4091 for (int i = 0; i < length; i++) {
4092 Object* entry = contents->get(i);
4093 if (entry->IsString()) {
4094 copy->set(i, entry);
4095 } else {
4096 ASSERT(entry->IsNumber());
4097 HandleScope scope;
4098 Handle<Object> entry_handle(entry);
4099 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4100 copy->set(i, *entry_str);
4101 }
4102 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004103 return *Factory::NewJSArrayWithElements(copy);
4104}
4105
4106
lrn@chromium.org303ada72010-10-27 09:33:13 +00004107static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004108 NoHandleAllocation ha;
4109 ASSERT(args.length() == 1);
4110
4111 // Compute the frame holding the arguments.
4112 JavaScriptFrameIterator it;
4113 it.AdvanceToArgumentsFrame();
4114 JavaScriptFrame* frame = it.frame();
4115
4116 // Get the actual number of provided arguments.
4117 const uint32_t n = frame->GetProvidedParametersCount();
4118
4119 // Try to convert the key to an index. If successful and within
4120 // index return the the argument from the frame.
4121 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004122 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004123 return frame->GetParameter(index);
4124 }
4125
4126 // Convert the key to a string.
4127 HandleScope scope;
4128 bool exception = false;
4129 Handle<Object> converted =
4130 Execution::ToString(args.at<Object>(0), &exception);
4131 if (exception) return Failure::Exception();
4132 Handle<String> key = Handle<String>::cast(converted);
4133
4134 // Try to convert the string key into an array index.
4135 if (key->AsArrayIndex(&index)) {
4136 if (index < n) {
4137 return frame->GetParameter(index);
4138 } else {
4139 return Top::initial_object_prototype()->GetElement(index);
4140 }
4141 }
4142
4143 // Handle special arguments properties.
4144 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4145 if (key->Equals(Heap::callee_symbol())) return frame->function();
4146
4147 // Lookup in the initial Object.prototype object.
4148 return Top::initial_object_prototype()->GetProperty(*key);
4149}
4150
4151
lrn@chromium.org303ada72010-10-27 09:33:13 +00004152static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004153 HandleScope scope;
4154
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004155 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004156 Handle<Object> object = args.at<Object>(0);
4157 if (object->IsJSObject()) {
4158 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004159 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004160 MaybeObject* ok = js_object->TransformToFastProperties(0);
4161 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004162 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004163 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004164 return *object;
4165}
4166
4167
lrn@chromium.org303ada72010-10-27 09:33:13 +00004168static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004169 HandleScope scope;
4170
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004171 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004172 Handle<Object> object = args.at<Object>(0);
4173 if (object->IsJSObject()) {
4174 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004175 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004176 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004177 return *object;
4178}
4179
4180
lrn@chromium.org303ada72010-10-27 09:33:13 +00004181static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004182 NoHandleAllocation ha;
4183 ASSERT(args.length() == 1);
4184
4185 return args[0]->ToBoolean();
4186}
4187
4188
4189// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4190// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004191static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004192 NoHandleAllocation ha;
4193
4194 Object* obj = args[0];
4195 if (obj->IsNumber()) return Heap::number_symbol();
4196 HeapObject* heap_obj = HeapObject::cast(obj);
4197
4198 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004199 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004200
4201 InstanceType instance_type = heap_obj->map()->instance_type();
4202 if (instance_type < FIRST_NONSTRING_TYPE) {
4203 return Heap::string_symbol();
4204 }
4205
4206 switch (instance_type) {
4207 case ODDBALL_TYPE:
4208 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4209 return Heap::boolean_symbol();
4210 }
4211 if (heap_obj->IsNull()) {
4212 return Heap::object_symbol();
4213 }
4214 ASSERT(heap_obj->IsUndefined());
4215 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004216 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004217 return Heap::function_symbol();
4218 default:
4219 // For any kind of object not handled above, the spec rule for
4220 // host objects gives that it is okay to return "object"
4221 return Heap::object_symbol();
4222 }
4223}
4224
4225
lrn@chromium.org25156de2010-04-06 13:10:27 +00004226static bool AreDigits(const char*s, int from, int to) {
4227 for (int i = from; i < to; i++) {
4228 if (s[i] < '0' || s[i] > '9') return false;
4229 }
4230
4231 return true;
4232}
4233
4234
4235static int ParseDecimalInteger(const char*s, int from, int to) {
4236 ASSERT(to - from < 10); // Overflow is not possible.
4237 ASSERT(from < to);
4238 int d = s[from] - '0';
4239
4240 for (int i = from + 1; i < to; i++) {
4241 d = 10 * d + (s[i] - '0');
4242 }
4243
4244 return d;
4245}
4246
4247
lrn@chromium.org303ada72010-10-27 09:33:13 +00004248static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004249 NoHandleAllocation ha;
4250 ASSERT(args.length() == 1);
4251 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004252 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004253
4254 // Fast case: short integer or some sorts of junk values.
4255 int len = subject->length();
4256 if (subject->IsSeqAsciiString()) {
4257 if (len == 0) return Smi::FromInt(0);
4258
4259 char const* data = SeqAsciiString::cast(subject)->GetChars();
4260 bool minus = (data[0] == '-');
4261 int start_pos = (minus ? 1 : 0);
4262
4263 if (start_pos == len) {
4264 return Heap::nan_value();
4265 } else if (data[start_pos] > '9') {
4266 // Fast check for a junk value. A valid string may start from a
4267 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4268 // the 'I' character ('Infinity'). All of that have codes not greater than
4269 // '9' except 'I'.
4270 if (data[start_pos] != 'I') {
4271 return Heap::nan_value();
4272 }
4273 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4274 // The maximal/minimal smi has 10 digits. If the string has less digits we
4275 // know it will fit into the smi-data type.
4276 int d = ParseDecimalInteger(data, start_pos, len);
4277 if (minus) {
4278 if (d == 0) return Heap::minus_zero_value();
4279 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004280 } else if (!subject->HasHashCode() &&
4281 len <= String::kMaxArrayIndexSize &&
4282 (len == 1 || data[0] != '0')) {
4283 // String hash is not calculated yet but all the data are present.
4284 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004285 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004286#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004287 subject->Hash(); // Force hash calculation.
4288 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4289 static_cast<int>(hash));
4290#endif
4291 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004292 }
4293 return Smi::FromInt(d);
4294 }
4295 }
4296
4297 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004298 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4299}
4300
4301
lrn@chromium.org303ada72010-10-27 09:33:13 +00004302static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004303 NoHandleAllocation ha;
4304 ASSERT(args.length() == 1);
4305
4306 CONVERT_CHECKED(JSArray, codes, args[0]);
4307 int length = Smi::cast(codes->length())->value();
4308
4309 // Check if the string can be ASCII.
4310 int i;
4311 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004312 Object* element;
4313 { MaybeObject* maybe_element = codes->GetElement(i);
4314 // We probably can't get an exception here, but just in order to enforce
4315 // the checking of inputs in the runtime calls we check here.
4316 if (!maybe_element->ToObject(&element)) return maybe_element;
4317 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004318 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4319 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4320 break;
4321 }
4322
lrn@chromium.org303ada72010-10-27 09:33:13 +00004323 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004324 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004325 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004326 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004327 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004328 }
4329
lrn@chromium.org303ada72010-10-27 09:33:13 +00004330 Object* object = NULL;
4331 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004332 String* result = String::cast(object);
4333 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004334 Object* element;
4335 { MaybeObject* maybe_element = codes->GetElement(i);
4336 if (!maybe_element->ToObject(&element)) return maybe_element;
4337 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004338 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004339 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004340 }
4341 return result;
4342}
4343
4344
4345// kNotEscaped is generated by the following:
4346//
4347// #!/bin/perl
4348// for (my $i = 0; $i < 256; $i++) {
4349// print "\n" if $i % 16 == 0;
4350// my $c = chr($i);
4351// my $escaped = 1;
4352// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4353// print $escaped ? "0, " : "1, ";
4354// }
4355
4356
4357static bool IsNotEscaped(uint16_t character) {
4358 // Only for 8 bit characters, the rest are always escaped (in a different way)
4359 ASSERT(character < 256);
4360 static const char kNotEscaped[256] = {
4361 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4364 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4365 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4366 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4367 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4368 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4372 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4376 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4377 };
4378 return kNotEscaped[character] != 0;
4379}
4380
4381
lrn@chromium.org303ada72010-10-27 09:33:13 +00004382static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004383 const char hex_chars[] = "0123456789ABCDEF";
4384 NoHandleAllocation ha;
4385 ASSERT(args.length() == 1);
4386 CONVERT_CHECKED(String, source, args[0]);
4387
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004388 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004389
4390 int escaped_length = 0;
4391 int length = source->length();
4392 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004393 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004394 buffer->Reset(source);
4395 while (buffer->has_more()) {
4396 uint16_t character = buffer->GetNext();
4397 if (character >= 256) {
4398 escaped_length += 6;
4399 } else if (IsNotEscaped(character)) {
4400 escaped_length++;
4401 } else {
4402 escaped_length += 3;
4403 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004404 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004405 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004406 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004407 Top::context()->mark_out_of_memory();
4408 return Failure::OutOfMemoryException();
4409 }
4410 }
4411 }
4412 // No length change implies no change. Return original string if no change.
4413 if (escaped_length == length) {
4414 return source;
4415 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004416 Object* o;
4417 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4418 if (!maybe_o->ToObject(&o)) return maybe_o;
4419 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004420 String* destination = String::cast(o);
4421 int dest_position = 0;
4422
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004423 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004424 buffer->Rewind();
4425 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004426 uint16_t chr = buffer->GetNext();
4427 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004428 destination->Set(dest_position, '%');
4429 destination->Set(dest_position+1, 'u');
4430 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4431 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4432 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4433 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004434 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004435 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004436 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004437 dest_position++;
4438 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004439 destination->Set(dest_position, '%');
4440 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4441 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004442 dest_position += 3;
4443 }
4444 }
4445 return destination;
4446}
4447
4448
4449static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4450 static const signed char kHexValue['g'] = {
4451 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4452 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4453 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4454 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4455 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4456 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4457 -1, 10, 11, 12, 13, 14, 15 };
4458
4459 if (character1 > 'f') return -1;
4460 int hi = kHexValue[character1];
4461 if (hi == -1) return -1;
4462 if (character2 > 'f') return -1;
4463 int lo = kHexValue[character2];
4464 if (lo == -1) return -1;
4465 return (hi << 4) + lo;
4466}
4467
4468
ager@chromium.org870a0b62008-11-04 11:43:05 +00004469static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004470 int i,
4471 int length,
4472 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004473 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004474 int32_t hi = 0;
4475 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004476 if (character == '%' &&
4477 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004478 source->Get(i + 1) == 'u' &&
4479 (hi = TwoDigitHex(source->Get(i + 2),
4480 source->Get(i + 3))) != -1 &&
4481 (lo = TwoDigitHex(source->Get(i + 4),
4482 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004483 *step = 6;
4484 return (hi << 8) + lo;
4485 } else if (character == '%' &&
4486 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004487 (lo = TwoDigitHex(source->Get(i + 1),
4488 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004489 *step = 3;
4490 return lo;
4491 } else {
4492 *step = 1;
4493 return character;
4494 }
4495}
4496
4497
lrn@chromium.org303ada72010-10-27 09:33:13 +00004498static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004499 NoHandleAllocation ha;
4500 ASSERT(args.length() == 1);
4501 CONVERT_CHECKED(String, source, args[0]);
4502
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004503 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004504
4505 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004506 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004507
4508 int unescaped_length = 0;
4509 for (int i = 0; i < length; unescaped_length++) {
4510 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004511 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004512 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004513 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004514 i += step;
4515 }
4516
4517 // No length change implies no change. Return original string if no change.
4518 if (unescaped_length == length)
4519 return source;
4520
lrn@chromium.org303ada72010-10-27 09:33:13 +00004521 Object* o;
4522 { MaybeObject* maybe_o = ascii ?
4523 Heap::AllocateRawAsciiString(unescaped_length) :
4524 Heap::AllocateRawTwoByteString(unescaped_length);
4525 if (!maybe_o->ToObject(&o)) return maybe_o;
4526 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004527 String* destination = String::cast(o);
4528
4529 int dest_position = 0;
4530 for (int i = 0; i < length; dest_position++) {
4531 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004532 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004533 i += step;
4534 }
4535 return destination;
4536}
4537
4538
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004539static const unsigned int kQuoteTableLength = 128u;
4540
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004541static const int kJsonQuotesCharactersPerEntry = 8;
4542static const char* const JsonQuotes =
4543 "\\u0000 \\u0001 \\u0002 \\u0003 "
4544 "\\u0004 \\u0005 \\u0006 \\u0007 "
4545 "\\b \\t \\n \\u000b "
4546 "\\f \\r \\u000e \\u000f "
4547 "\\u0010 \\u0011 \\u0012 \\u0013 "
4548 "\\u0014 \\u0015 \\u0016 \\u0017 "
4549 "\\u0018 \\u0019 \\u001a \\u001b "
4550 "\\u001c \\u001d \\u001e \\u001f "
4551 " ! \\\" # "
4552 "$ % & ' "
4553 "( ) * + "
4554 ", - . / "
4555 "0 1 2 3 "
4556 "4 5 6 7 "
4557 "8 9 : ; "
4558 "< = > ? "
4559 "@ A B C "
4560 "D E F G "
4561 "H I J K "
4562 "L M N O "
4563 "P Q R S "
4564 "T U V W "
4565 "X Y Z [ "
4566 "\\\\ ] ^ _ "
4567 "` a b c "
4568 "d e f g "
4569 "h i j k "
4570 "l m n o "
4571 "p q r s "
4572 "t u v w "
4573 "x y z { "
4574 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004575
4576
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004577// For a string that is less than 32k characters it should always be
4578// possible to allocate it in new space.
4579static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4580
4581
4582// Doing JSON quoting cannot make the string more than this many times larger.
4583static const int kJsonQuoteWorstCaseBlowup = 6;
4584
4585
4586// Covers the entire ASCII range (all other characters are unchanged by JSON
4587// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004588static const byte JsonQuoteLengths[kQuoteTableLength] = {
4589 6, 6, 6, 6, 6, 6, 6, 6,
4590 2, 2, 2, 6, 2, 2, 6, 6,
4591 6, 6, 6, 6, 6, 6, 6, 6,
4592 6, 6, 6, 6, 6, 6, 6, 6,
4593 1, 1, 2, 1, 1, 1, 1, 1,
4594 1, 1, 1, 1, 1, 1, 1, 1,
4595 1, 1, 1, 1, 1, 1, 1, 1,
4596 1, 1, 1, 1, 1, 1, 1, 1,
4597 1, 1, 1, 1, 1, 1, 1, 1,
4598 1, 1, 1, 1, 1, 1, 1, 1,
4599 1, 1, 1, 1, 1, 1, 1, 1,
4600 1, 1, 1, 1, 2, 1, 1, 1,
4601 1, 1, 1, 1, 1, 1, 1, 1,
4602 1, 1, 1, 1, 1, 1, 1, 1,
4603 1, 1, 1, 1, 1, 1, 1, 1,
4604 1, 1, 1, 1, 1, 1, 1, 1,
4605};
4606
4607
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004608template <typename StringType>
4609MaybeObject* AllocateRawString(int length);
4610
4611
4612template <>
4613MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4614 return Heap::AllocateRawTwoByteString(length);
4615}
4616
4617
4618template <>
4619MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4620 return Heap::AllocateRawAsciiString(length);
4621}
4622
4623
4624template <typename Char, typename StringType>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004625static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004626 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004627 const Char* read_cursor = characters.start();
4628 const Char* end = read_cursor + length;
4629 const int kSpaceForQuotes = 2;
4630 int quoted_length = kSpaceForQuotes;
4631 while (read_cursor < end) {
4632 Char c = *(read_cursor++);
4633 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4634 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004635 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004636 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004637 }
4638 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004639 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4640 Object* new_object;
4641 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004642 return new_alloc;
4643 }
4644 StringType* new_string = StringType::cast(new_object);
4645
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004646 Char* write_cursor = reinterpret_cast<Char*>(
4647 new_string->address() + SeqAsciiString::kHeaderSize);
4648 *(write_cursor++) = '"';
4649
4650 read_cursor = characters.start();
4651 while (read_cursor < end) {
4652 Char c = *(read_cursor++);
4653 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4654 *(write_cursor++) = c;
4655 } else {
4656 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4657 const char* replacement = JsonQuotes +
4658 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4659 for (int i = 0; i < len; i++) {
4660 *write_cursor++ = *replacement++;
4661 }
4662 }
4663 }
4664 *(write_cursor++) = '"';
4665 return new_string;
4666}
4667
4668
4669template <typename Char, typename StringType>
4670static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4671 int length = characters.length();
4672 Counters::quote_json_char_count.Increment(length);
4673 const int kSpaceForQuotes = 2;
4674 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4675 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
4676 return SlowQuoteJsonString<Char, StringType>(characters);
4677 }
4678
4679 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4680 Object* new_object;
4681 if (!new_alloc->ToObject(&new_object)) {
4682 return new_alloc;
4683 }
4684 if (!Heap::new_space()->Contains(new_object)) {
4685 // Even if our string is small enough to fit in new space we still have to
4686 // handle it being allocated in old space as may happen in the third
4687 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
4688 // CEntryStub::GenerateCore.
4689 return SlowQuoteJsonString<Char, StringType>(characters);
4690 }
4691 StringType* new_string = StringType::cast(new_object);
4692 ASSERT(Heap::new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004693
4694 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4695 Char* write_cursor = reinterpret_cast<Char*>(
4696 new_string->address() + SeqAsciiString::kHeaderSize);
4697 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004698
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004699 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004700 const Char* end = read_cursor + length;
4701 while (read_cursor < end) {
4702 Char c = *(read_cursor++);
4703 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4704 *(write_cursor++) = c;
4705 } else {
4706 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4707 const char* replacement = JsonQuotes +
4708 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4709 write_cursor[0] = replacement[0];
4710 if (len > 1) {
4711 write_cursor[1] = replacement[1];
4712 if (len > 2) {
4713 ASSERT(len == 6);
4714 write_cursor[2] = replacement[2];
4715 write_cursor[3] = replacement[3];
4716 write_cursor[4] = replacement[4];
4717 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004718 }
4719 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004720 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004721 }
4722 }
4723 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004724
4725 int final_length = static_cast<int>(
4726 write_cursor - reinterpret_cast<Char*>(
4727 new_string->address() + SeqAsciiString::kHeaderSize));
4728 Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4729 final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004730 return new_string;
4731}
4732
4733
4734static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4735 NoHandleAllocation ha;
4736 CONVERT_CHECKED(String, str, args[0]);
4737 if (!str->IsFlat()) {
4738 MaybeObject* try_flatten = str->TryFlatten();
4739 Object* flat;
4740 if (!try_flatten->ToObject(&flat)) {
4741 return try_flatten;
4742 }
4743 str = String::cast(flat);
4744 ASSERT(str->IsFlat());
4745 }
4746 if (str->IsTwoByteRepresentation()) {
4747 return QuoteJsonString<uc16, SeqTwoByteString>(str->ToUC16Vector());
4748 } else {
4749 return QuoteJsonString<char, SeqAsciiString>(str->ToAsciiVector());
4750 }
4751}
4752
4753
4754
lrn@chromium.org303ada72010-10-27 09:33:13 +00004755static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004756 NoHandleAllocation ha;
4757
4758 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004759 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004760
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004761 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004762
lrn@chromium.org25156de2010-04-06 13:10:27 +00004763 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4764 double value = StringToInt(s, radix);
4765 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004766}
4767
4768
lrn@chromium.org303ada72010-10-27 09:33:13 +00004769static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004770 NoHandleAllocation ha;
4771 CONVERT_CHECKED(String, str, args[0]);
4772
4773 // ECMA-262 section 15.1.2.3, empty string is NaN
4774 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4775
4776 // Create a number object from the value.
4777 return Heap::NumberFromDouble(value);
4778}
4779
4780
4781static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4782static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4783
4784
4785template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004786MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
4787 String* s,
4788 int length,
4789 int input_string_length,
4790 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004791 // We try this twice, once with the assumption that the result is no longer
4792 // than the input and, if that assumption breaks, again with the exact
4793 // length. This may not be pretty, but it is nicer than what was here before
4794 // and I hereby claim my vaffel-is.
4795 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004796 // Allocate the resulting string.
4797 //
4798 // NOTE: This assumes that the upper/lower case of an ascii
4799 // character is also ascii. This is currently the case, but it
4800 // might break in the future if we implement more context and locale
4801 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004802 Object* o;
4803 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
4804 ? Heap::AllocateRawAsciiString(length)
4805 : Heap::AllocateRawTwoByteString(length);
4806 if (!maybe_o->ToObject(&o)) return maybe_o;
4807 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004808 String* result = String::cast(o);
4809 bool has_changed_character = false;
4810
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004811 // Convert all characters to upper case, assuming that they will fit
4812 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004813 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004815 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004816 // We can assume that the string is not empty
4817 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004818 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004819 bool has_next = buffer->has_more();
4820 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004821 int char_length = mapping->get(current, next, chars);
4822 if (char_length == 0) {
4823 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004824 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004825 i++;
4826 } else if (char_length == 1) {
4827 // Common case: converting the letter resulted in one character.
4828 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004829 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004830 has_changed_character = true;
4831 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004832 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004833 // We've assumed that the result would be as long as the
4834 // input but here is a character that converts to several
4835 // characters. No matter, we calculate the exact length
4836 // of the result and try the whole thing again.
4837 //
4838 // Note that this leaves room for optimization. We could just
4839 // memcpy what we already have to the result string. Also,
4840 // the result string is the last object allocated we could
4841 // "realloc" it and probably, in the vast majority of cases,
4842 // extend the existing string to be able to hold the full
4843 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004844 int next_length = 0;
4845 if (has_next) {
4846 next_length = mapping->get(next, 0, chars);
4847 if (next_length == 0) next_length = 1;
4848 }
4849 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004850 while (buffer->has_more()) {
4851 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004852 // NOTE: we use 0 as the next character here because, while
4853 // the next character may affect what a character converts to,
4854 // it does not in any case affect the length of what it convert
4855 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004856 int char_length = mapping->get(current, 0, chars);
4857 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00004858 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004859 if (current_length > Smi::kMaxValue) {
4860 Top::context()->mark_out_of_memory();
4861 return Failure::OutOfMemoryException();
4862 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004863 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004864 // Try again with the real length.
4865 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004866 } else {
4867 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004868 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004869 i++;
4870 }
4871 has_changed_character = true;
4872 }
4873 current = next;
4874 }
4875 if (has_changed_character) {
4876 return result;
4877 } else {
4878 // If we didn't actually change anything in doing the conversion
4879 // we simple return the result and let the converted string
4880 // become garbage; there is no reason to keep two identical strings
4881 // alive.
4882 return s;
4883 }
4884}
4885
4886
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004887namespace {
4888
lrn@chromium.org303ada72010-10-27 09:33:13 +00004889static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
4890
4891
4892// Given a word and two range boundaries returns a word with high bit
4893// set in every byte iff the corresponding input byte was strictly in
4894// the range (m, n). All the other bits in the result are cleared.
4895// This function is only useful when it can be inlined and the
4896// boundaries are statically known.
4897// Requires: all bytes in the input word and the boundaries must be
4898// ascii (less than 0x7F).
4899static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
4900 // Every byte in an ascii string is less than or equal to 0x7F.
4901 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
4902 // Use strict inequalities since in edge cases the function could be
4903 // further simplified.
4904 ASSERT(0 < m && m < n && n < 0x7F);
4905 // Has high bit set in every w byte less than n.
4906 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
4907 // Has high bit set in every w byte greater than m.
4908 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
4909 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
4910}
4911
4912
4913enum AsciiCaseConversion {
4914 ASCII_TO_LOWER,
4915 ASCII_TO_UPPER
4916};
4917
4918
4919template <AsciiCaseConversion dir>
4920struct FastAsciiConverter {
4921 static bool Convert(char* dst, char* src, int length) {
4922#ifdef DEBUG
4923 char* saved_dst = dst;
4924 char* saved_src = src;
4925#endif
4926 // We rely on the distance between upper and lower case letters
4927 // being a known power of 2.
4928 ASSERT('a' - 'A' == (1 << 5));
4929 // Boundaries for the range of input characters than require conversion.
4930 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
4931 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
4932 bool changed = false;
4933 char* const limit = src + length;
4934#ifdef V8_HOST_CAN_READ_UNALIGNED
4935 // Process the prefix of the input that requires no conversion one
4936 // (machine) word at a time.
4937 while (src <= limit - sizeof(uintptr_t)) {
4938 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4939 if (AsciiRangeMask(w, lo, hi) != 0) {
4940 changed = true;
4941 break;
4942 }
4943 *reinterpret_cast<uintptr_t*>(dst) = w;
4944 src += sizeof(uintptr_t);
4945 dst += sizeof(uintptr_t);
4946 }
4947 // Process the remainder of the input performing conversion when
4948 // required one word at a time.
4949 while (src <= limit - sizeof(uintptr_t)) {
4950 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4951 uintptr_t m = AsciiRangeMask(w, lo, hi);
4952 // The mask has high (7th) bit set in every byte that needs
4953 // conversion and we know that the distance between cases is
4954 // 1 << 5.
4955 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
4956 src += sizeof(uintptr_t);
4957 dst += sizeof(uintptr_t);
4958 }
4959#endif
4960 // Process the last few bytes of the input (or the whole input if
4961 // unaligned access is not supported).
4962 while (src < limit) {
4963 char c = *src;
4964 if (lo < c && c < hi) {
4965 c ^= (1 << 5);
4966 changed = true;
4967 }
4968 *dst = c;
4969 ++src;
4970 ++dst;
4971 }
4972#ifdef DEBUG
4973 CheckConvert(saved_dst, saved_src, length, changed);
4974#endif
4975 return changed;
4976 }
4977
4978#ifdef DEBUG
4979 static void CheckConvert(char* dst, char* src, int length, bool changed) {
4980 bool expected_changed = false;
4981 for (int i = 0; i < length; i++) {
4982 if (dst[i] == src[i]) continue;
4983 expected_changed = true;
4984 if (dir == ASCII_TO_LOWER) {
4985 ASSERT('A' <= src[i] && src[i] <= 'Z');
4986 ASSERT(dst[i] == src[i] + ('a' - 'A'));
4987 } else {
4988 ASSERT(dir == ASCII_TO_UPPER);
4989 ASSERT('a' <= src[i] && src[i] <= 'z');
4990 ASSERT(dst[i] == src[i] - ('a' - 'A'));
4991 }
4992 }
4993 ASSERT(expected_changed == changed);
4994 }
4995#endif
4996};
4997
4998
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004999struct ToLowerTraits {
5000 typedef unibrow::ToLowercase UnibrowConverter;
5001
lrn@chromium.org303ada72010-10-27 09:33:13 +00005002 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005003};
5004
5005
5006struct ToUpperTraits {
5007 typedef unibrow::ToUppercase UnibrowConverter;
5008
lrn@chromium.org303ada72010-10-27 09:33:13 +00005009 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005010};
5011
5012} // namespace
5013
5014
5015template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005016MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005017 Arguments args,
5018 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005019 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005020 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005021 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005022
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005023 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005024 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005025 if (length == 0) return s;
5026
5027 // Simpler handling of ascii strings.
5028 //
5029 // NOTE: This assumes that the upper/lower case of an ascii
5030 // character is also ascii. This is currently the case, but it
5031 // might break in the future if we implement more context and locale
5032 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005033 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005034 Object* o;
5035 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
5036 if (!maybe_o->ToObject(&o)) return maybe_o;
5037 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005038 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005039 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005040 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005041 return has_changed_character ? result : s;
5042 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005043
lrn@chromium.org303ada72010-10-27 09:33:13 +00005044 Object* answer;
5045 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
5046 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5047 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005048 if (answer->IsSmi()) {
5049 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005050 { MaybeObject* maybe_answer =
5051 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
5052 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5053 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005054 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005055 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005056}
5057
5058
lrn@chromium.org303ada72010-10-27 09:33:13 +00005059static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005060 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005061}
5062
5063
lrn@chromium.org303ada72010-10-27 09:33:13 +00005064static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005065 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005066}
5067
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005068
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005069static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5070 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5071}
5072
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005073
lrn@chromium.org303ada72010-10-27 09:33:13 +00005074static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005075 NoHandleAllocation ha;
5076 ASSERT(args.length() == 3);
5077
5078 CONVERT_CHECKED(String, s, args[0]);
5079 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5080 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5081
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005082 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005083 int length = s->length();
5084
5085 int left = 0;
5086 if (trimLeft) {
5087 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5088 left++;
5089 }
5090 }
5091
5092 int right = length;
5093 if (trimRight) {
5094 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5095 right--;
5096 }
5097 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005098 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005099}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005100
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005101
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005102template <typename SubjectChar, typename PatternChar>
5103void FindStringIndices(Vector<const SubjectChar> subject,
5104 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005105 ZoneList<int>* indices,
5106 unsigned int limit) {
5107 ASSERT(limit > 0);
5108 // Collect indices of pattern in subject, and the end-of-string index.
5109 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005110 StringSearch<PatternChar, SubjectChar> search(pattern);
5111 int pattern_length = pattern.length();
5112 int index = 0;
5113 while (limit > 0) {
5114 index = search.Search(subject, index);
5115 if (index < 0) return;
5116 indices->Add(index);
5117 index += pattern_length;
5118 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005119 }
5120}
5121
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005122
lrn@chromium.org303ada72010-10-27 09:33:13 +00005123static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005124 ASSERT(args.length() == 3);
5125 HandleScope handle_scope;
5126 CONVERT_ARG_CHECKED(String, subject, 0);
5127 CONVERT_ARG_CHECKED(String, pattern, 1);
5128 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5129
5130 int subject_length = subject->length();
5131 int pattern_length = pattern->length();
5132 RUNTIME_ASSERT(pattern_length > 0);
5133
5134 // The limit can be very large (0xffffffffu), but since the pattern
5135 // isn't empty, we can never create more parts than ~half the length
5136 // of the subject.
5137
5138 if (!subject->IsFlat()) FlattenString(subject);
5139
5140 static const int kMaxInitialListCapacity = 16;
5141
5142 ZoneScope scope(DELETE_ON_EXIT);
5143
5144 // Find (up to limit) indices of separator and end-of-string in subject
5145 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5146 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005147 if (!pattern->IsFlat()) FlattenString(pattern);
5148
5149 // No allocation block.
5150 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005151 AssertNoAllocation nogc;
5152 if (subject->IsAsciiRepresentation()) {
5153 Vector<const char> subject_vector = subject->ToAsciiVector();
5154 if (pattern->IsAsciiRepresentation()) {
5155 FindStringIndices(subject_vector,
5156 pattern->ToAsciiVector(),
5157 &indices,
5158 limit);
5159 } else {
5160 FindStringIndices(subject_vector,
5161 pattern->ToUC16Vector(),
5162 &indices,
5163 limit);
5164 }
5165 } else {
5166 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5167 if (pattern->IsAsciiRepresentation()) {
5168 FindStringIndices(subject_vector,
5169 pattern->ToAsciiVector(),
5170 &indices,
5171 limit);
5172 } else {
5173 FindStringIndices(subject_vector,
5174 pattern->ToUC16Vector(),
5175 &indices,
5176 limit);
5177 }
5178 }
5179 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005180
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005181 if (static_cast<uint32_t>(indices.length()) < limit) {
5182 indices.Add(subject_length);
5183 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005184
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005185 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005186
5187 // Create JSArray of substrings separated by separator.
5188 int part_count = indices.length();
5189
5190 Handle<JSArray> result = Factory::NewJSArray(part_count);
5191 result->set_length(Smi::FromInt(part_count));
5192
5193 ASSERT(result->HasFastElements());
5194
5195 if (part_count == 1 && indices.at(0) == subject_length) {
5196 FixedArray::cast(result->elements())->set(0, *subject);
5197 return *result;
5198 }
5199
5200 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5201 int part_start = 0;
5202 for (int i = 0; i < part_count; i++) {
5203 HandleScope local_loop_handle;
5204 int part_end = indices.at(i);
5205 Handle<String> substring =
5206 Factory::NewSubString(subject, part_start, part_end);
5207 elements->set(i, *substring);
5208 part_start = part_end + pattern_length;
5209 }
5210
5211 return *result;
5212}
5213
5214
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005215// Copies ascii characters to the given fixed array looking up
5216// one-char strings in the cache. Gives up on the first char that is
5217// not in the cache and fills the remainder with smi zeros. Returns
5218// the length of the successfully copied prefix.
5219static int CopyCachedAsciiCharsToArray(const char* chars,
5220 FixedArray* elements,
5221 int length) {
5222 AssertNoAllocation nogc;
5223 FixedArray* ascii_cache = Heap::single_character_string_cache();
5224 Object* undefined = Heap::undefined_value();
5225 int i;
5226 for (i = 0; i < length; ++i) {
5227 Object* value = ascii_cache->get(chars[i]);
5228 if (value == undefined) break;
5229 ASSERT(!Heap::InNewSpace(value));
5230 elements->set(i, value, SKIP_WRITE_BARRIER);
5231 }
5232 if (i < length) {
5233 ASSERT(Smi::FromInt(0) == 0);
5234 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5235 }
5236#ifdef DEBUG
5237 for (int j = 0; j < length; ++j) {
5238 Object* element = elements->get(j);
5239 ASSERT(element == Smi::FromInt(0) ||
5240 (element->IsString() && String::cast(element)->LooksValid()));
5241 }
5242#endif
5243 return i;
5244}
5245
5246
5247// Converts a String to JSArray.
5248// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005249static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005250 HandleScope scope;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005251 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005252 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005253 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005254
5255 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005256 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005257
5258 Handle<FixedArray> elements;
5259 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005260 Object* obj;
5261 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5262 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5263 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005264 elements = Handle<FixedArray>(FixedArray::cast(obj));
5265
5266 Vector<const char> chars = s->ToAsciiVector();
5267 // Note, this will initialize all elements (not only the prefix)
5268 // to prevent GC from seeing partially initialized array.
5269 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5270 *elements,
5271 length);
5272
5273 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005274 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5275 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005276 }
5277 } else {
5278 elements = Factory::NewFixedArray(length);
5279 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005280 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5281 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005282 }
5283 }
5284
5285#ifdef DEBUG
5286 for (int i = 0; i < length; ++i) {
5287 ASSERT(String::cast(elements->get(i))->length() == 1);
5288 }
5289#endif
5290
5291 return *Factory::NewJSArrayWithElements(elements);
5292}
5293
5294
lrn@chromium.org303ada72010-10-27 09:33:13 +00005295static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005296 NoHandleAllocation ha;
5297 ASSERT(args.length() == 1);
5298 CONVERT_CHECKED(String, value, args[0]);
5299 return value->ToObject();
5300}
5301
5302
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005303bool Runtime::IsUpperCaseChar(uint16_t ch) {
5304 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5305 int char_length = to_upper_mapping.get(ch, 0, chars);
5306 return char_length == 0;
5307}
5308
5309
lrn@chromium.org303ada72010-10-27 09:33:13 +00005310static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005311 NoHandleAllocation ha;
5312 ASSERT(args.length() == 1);
5313
5314 Object* number = args[0];
5315 RUNTIME_ASSERT(number->IsNumber());
5316
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005317 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005318}
5319
5320
lrn@chromium.org303ada72010-10-27 09:33:13 +00005321static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005322 NoHandleAllocation ha;
5323 ASSERT(args.length() == 1);
5324
5325 Object* number = args[0];
5326 RUNTIME_ASSERT(number->IsNumber());
5327
5328 return Heap::NumberToString(number, false);
5329}
5330
5331
lrn@chromium.org303ada72010-10-27 09:33:13 +00005332static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005333 NoHandleAllocation ha;
5334 ASSERT(args.length() == 1);
5335
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005336 CONVERT_DOUBLE_CHECKED(number, args[0]);
5337
5338 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5339 if (number > 0 && number <= Smi::kMaxValue) {
5340 return Smi::FromInt(static_cast<int>(number));
5341 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005342 return Heap::NumberFromDouble(DoubleToInteger(number));
5343}
5344
5345
lrn@chromium.org303ada72010-10-27 09:33:13 +00005346static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005347 NoHandleAllocation ha;
5348 ASSERT(args.length() == 1);
5349
5350 CONVERT_DOUBLE_CHECKED(number, args[0]);
5351
5352 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5353 if (number > 0 && number <= Smi::kMaxValue) {
5354 return Smi::FromInt(static_cast<int>(number));
5355 }
5356
5357 double double_value = DoubleToInteger(number);
5358 // Map both -0 and +0 to +0.
5359 if (double_value == 0) double_value = 0;
5360
5361 return Heap::NumberFromDouble(double_value);
5362}
5363
5364
lrn@chromium.org303ada72010-10-27 09:33:13 +00005365static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005366 NoHandleAllocation ha;
5367 ASSERT(args.length() == 1);
5368
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005369 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005370 return Heap::NumberFromUint32(number);
5371}
5372
5373
lrn@chromium.org303ada72010-10-27 09:33:13 +00005374static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005375 NoHandleAllocation ha;
5376 ASSERT(args.length() == 1);
5377
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005378 CONVERT_DOUBLE_CHECKED(number, args[0]);
5379
5380 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5381 if (number > 0 && number <= Smi::kMaxValue) {
5382 return Smi::FromInt(static_cast<int>(number));
5383 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005384 return Heap::NumberFromInt32(DoubleToInt32(number));
5385}
5386
5387
ager@chromium.org870a0b62008-11-04 11:43:05 +00005388// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5389// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005390static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005391 NoHandleAllocation ha;
5392 ASSERT(args.length() == 1);
5393
5394 Object* obj = args[0];
5395 if (obj->IsSmi()) {
5396 return obj;
5397 }
5398 if (obj->IsHeapNumber()) {
5399 double value = HeapNumber::cast(obj)->value();
5400 int int_value = FastD2I(value);
5401 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5402 return Smi::FromInt(int_value);
5403 }
5404 }
5405 return Heap::nan_value();
5406}
5407
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005408
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005409static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
5410 NoHandleAllocation ha;
5411 ASSERT(args.length() == 0);
5412 return Heap::AllocateHeapNumber(0);
5413}
5414
5415
lrn@chromium.org303ada72010-10-27 09:33:13 +00005416static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005417 NoHandleAllocation ha;
5418 ASSERT(args.length() == 2);
5419
5420 CONVERT_DOUBLE_CHECKED(x, args[0]);
5421 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005422 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005423}
5424
5425
lrn@chromium.org303ada72010-10-27 09:33:13 +00005426static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005427 NoHandleAllocation ha;
5428 ASSERT(args.length() == 2);
5429
5430 CONVERT_DOUBLE_CHECKED(x, args[0]);
5431 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005432 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005433}
5434
5435
lrn@chromium.org303ada72010-10-27 09:33:13 +00005436static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005437 NoHandleAllocation ha;
5438 ASSERT(args.length() == 2);
5439
5440 CONVERT_DOUBLE_CHECKED(x, args[0]);
5441 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005442 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005443}
5444
5445
lrn@chromium.org303ada72010-10-27 09:33:13 +00005446static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005447 NoHandleAllocation ha;
5448 ASSERT(args.length() == 1);
5449
5450 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005451 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005452}
5453
5454
lrn@chromium.org303ada72010-10-27 09:33:13 +00005455static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005456 NoHandleAllocation ha;
5457 ASSERT(args.length() == 0);
5458
5459 return Heap::NumberFromDouble(9876543210.0);
5460}
5461
5462
lrn@chromium.org303ada72010-10-27 09:33:13 +00005463static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005464 NoHandleAllocation ha;
5465 ASSERT(args.length() == 2);
5466
5467 CONVERT_DOUBLE_CHECKED(x, args[0]);
5468 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005469 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005470}
5471
5472
lrn@chromium.org303ada72010-10-27 09:33:13 +00005473static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005474 NoHandleAllocation ha;
5475 ASSERT(args.length() == 2);
5476
5477 CONVERT_DOUBLE_CHECKED(x, args[0]);
5478 CONVERT_DOUBLE_CHECKED(y, args[1]);
5479
ager@chromium.org3811b432009-10-28 14:53:37 +00005480 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005481 // NumberFromDouble may return a Smi instead of a Number object
5482 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005483}
5484
5485
lrn@chromium.org303ada72010-10-27 09:33:13 +00005486static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005487 NoHandleAllocation ha;
5488 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005489 CONVERT_CHECKED(String, str1, args[0]);
5490 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005491 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005492 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005493}
5494
5495
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005496template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005497static inline void StringBuilderConcatHelper(String* special,
5498 sinkchar* sink,
5499 FixedArray* fixed_array,
5500 int array_length) {
5501 int position = 0;
5502 for (int i = 0; i < array_length; i++) {
5503 Object* element = fixed_array->get(i);
5504 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005505 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005506 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005507 int pos;
5508 int len;
5509 if (encoded_slice > 0) {
5510 // Position and length encoded in one smi.
5511 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5512 len = StringBuilderSubstringLength::decode(encoded_slice);
5513 } else {
5514 // Position and length encoded in two smis.
5515 Object* obj = fixed_array->get(++i);
5516 ASSERT(obj->IsSmi());
5517 pos = Smi::cast(obj)->value();
5518 len = -encoded_slice;
5519 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005520 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005521 sink + position,
5522 pos,
5523 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005524 position += len;
5525 } else {
5526 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005527 int element_length = string->length();
5528 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005529 position += element_length;
5530 }
5531 }
5532}
5533
5534
lrn@chromium.org303ada72010-10-27 09:33:13 +00005535static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005536 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005537 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005538 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005539 if (!args[1]->IsSmi()) {
5540 Top::context()->mark_out_of_memory();
5541 return Failure::OutOfMemoryException();
5542 }
5543 int array_length = Smi::cast(args[1])->value();
5544 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005545
5546 // This assumption is used by the slice encoding in one or two smis.
5547 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5548
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005549 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005550 if (!array->HasFastElements()) {
5551 return Top::Throw(Heap::illegal_argument_symbol());
5552 }
5553 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005554 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005555 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005556 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005557
5558 if (array_length == 0) {
5559 return Heap::empty_string();
5560 } else if (array_length == 1) {
5561 Object* first = fixed_array->get(0);
5562 if (first->IsString()) return first;
5563 }
5564
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005565 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005566 int position = 0;
5567 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005568 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005569 Object* elt = fixed_array->get(i);
5570 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005571 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005572 int smi_value = Smi::cast(elt)->value();
5573 int pos;
5574 int len;
5575 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005576 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005577 pos = StringBuilderSubstringPosition::decode(smi_value);
5578 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005579 } else {
5580 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005581 len = -smi_value;
5582 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005583 i++;
5584 if (i >= array_length) {
5585 return Top::Throw(Heap::illegal_argument_symbol());
5586 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005587 Object* next_smi = fixed_array->get(i);
5588 if (!next_smi->IsSmi()) {
5589 return Top::Throw(Heap::illegal_argument_symbol());
5590 }
5591 pos = Smi::cast(next_smi)->value();
5592 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005593 return Top::Throw(Heap::illegal_argument_symbol());
5594 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005595 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005596 ASSERT(pos >= 0);
5597 ASSERT(len >= 0);
5598 if (pos > special_length || len > special_length - pos) {
5599 return Top::Throw(Heap::illegal_argument_symbol());
5600 }
5601 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005602 } else if (elt->IsString()) {
5603 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005604 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005605 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005606 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005607 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005608 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005609 } else {
5610 return Top::Throw(Heap::illegal_argument_symbol());
5611 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005612 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005613 Top::context()->mark_out_of_memory();
5614 return Failure::OutOfMemoryException();
5615 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005616 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005617 }
5618
5619 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005620 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005621
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005622 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005623 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5624 if (!maybe_object->ToObject(&object)) return maybe_object;
5625 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005626 SeqAsciiString* answer = SeqAsciiString::cast(object);
5627 StringBuilderConcatHelper(special,
5628 answer->GetChars(),
5629 fixed_array,
5630 array_length);
5631 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005632 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005633 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5634 if (!maybe_object->ToObject(&object)) return maybe_object;
5635 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005636 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5637 StringBuilderConcatHelper(special,
5638 answer->GetChars(),
5639 fixed_array,
5640 array_length);
5641 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005642 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005643}
5644
5645
lrn@chromium.org303ada72010-10-27 09:33:13 +00005646static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005647 NoHandleAllocation ha;
5648 ASSERT(args.length() == 2);
5649
5650 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5651 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5652 return Heap::NumberFromInt32(x | y);
5653}
5654
5655
lrn@chromium.org303ada72010-10-27 09:33:13 +00005656static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005657 NoHandleAllocation ha;
5658 ASSERT(args.length() == 2);
5659
5660 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5661 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5662 return Heap::NumberFromInt32(x & y);
5663}
5664
5665
lrn@chromium.org303ada72010-10-27 09:33:13 +00005666static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005667 NoHandleAllocation ha;
5668 ASSERT(args.length() == 2);
5669
5670 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5671 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5672 return Heap::NumberFromInt32(x ^ y);
5673}
5674
5675
lrn@chromium.org303ada72010-10-27 09:33:13 +00005676static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005677 NoHandleAllocation ha;
5678 ASSERT(args.length() == 1);
5679
5680 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5681 return Heap::NumberFromInt32(~x);
5682}
5683
5684
lrn@chromium.org303ada72010-10-27 09:33:13 +00005685static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005686 NoHandleAllocation ha;
5687 ASSERT(args.length() == 2);
5688
5689 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5690 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5691 return Heap::NumberFromInt32(x << (y & 0x1f));
5692}
5693
5694
lrn@chromium.org303ada72010-10-27 09:33:13 +00005695static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005696 NoHandleAllocation ha;
5697 ASSERT(args.length() == 2);
5698
5699 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5700 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5701 return Heap::NumberFromUint32(x >> (y & 0x1f));
5702}
5703
5704
lrn@chromium.org303ada72010-10-27 09:33:13 +00005705static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005706 NoHandleAllocation ha;
5707 ASSERT(args.length() == 2);
5708
5709 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5710 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5711 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5712}
5713
5714
lrn@chromium.org303ada72010-10-27 09:33:13 +00005715static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005716 NoHandleAllocation ha;
5717 ASSERT(args.length() == 2);
5718
5719 CONVERT_DOUBLE_CHECKED(x, args[0]);
5720 CONVERT_DOUBLE_CHECKED(y, args[1]);
5721 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5722 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5723 if (x == y) return Smi::FromInt(EQUAL);
5724 Object* result;
5725 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5726 result = Smi::FromInt(EQUAL);
5727 } else {
5728 result = Smi::FromInt(NOT_EQUAL);
5729 }
5730 return result;
5731}
5732
5733
lrn@chromium.org303ada72010-10-27 09:33:13 +00005734static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005735 NoHandleAllocation ha;
5736 ASSERT(args.length() == 2);
5737
5738 CONVERT_CHECKED(String, x, args[0]);
5739 CONVERT_CHECKED(String, y, args[1]);
5740
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005741 bool not_equal = !x->Equals(y);
5742 // This is slightly convoluted because the value that signifies
5743 // equality is 0 and inequality is 1 so we have to negate the result
5744 // from String::Equals.
5745 ASSERT(not_equal == 0 || not_equal == 1);
5746 STATIC_CHECK(EQUAL == 0);
5747 STATIC_CHECK(NOT_EQUAL == 1);
5748 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005749}
5750
5751
lrn@chromium.org303ada72010-10-27 09:33:13 +00005752static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005753 NoHandleAllocation ha;
5754 ASSERT(args.length() == 3);
5755
5756 CONVERT_DOUBLE_CHECKED(x, args[0]);
5757 CONVERT_DOUBLE_CHECKED(y, args[1]);
5758 if (isnan(x) || isnan(y)) return args[2];
5759 if (x == y) return Smi::FromInt(EQUAL);
5760 if (isless(x, y)) return Smi::FromInt(LESS);
5761 return Smi::FromInt(GREATER);
5762}
5763
5764
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005765// Compare two Smis as if they were converted to strings and then
5766// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005767static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005768 NoHandleAllocation ha;
5769 ASSERT(args.length() == 2);
5770
5771 // Arrays for the individual characters of the two Smis. Smis are
5772 // 31 bit integers and 10 decimal digits are therefore enough.
5773 static int x_elms[10];
5774 static int y_elms[10];
5775
5776 // Extract the integer values from the Smis.
5777 CONVERT_CHECKED(Smi, x, args[0]);
5778 CONVERT_CHECKED(Smi, y, args[1]);
5779 int x_value = x->value();
5780 int y_value = y->value();
5781
5782 // If the integers are equal so are the string representations.
5783 if (x_value == y_value) return Smi::FromInt(EQUAL);
5784
5785 // If one of the integers are zero the normal integer order is the
5786 // same as the lexicographic order of the string representations.
5787 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5788
ager@chromium.org32912102009-01-16 10:38:43 +00005789 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005790 // smallest because the char code of '-' is less than the char code
5791 // of any digit. Otherwise, we make both values positive.
5792 if (x_value < 0 || y_value < 0) {
5793 if (y_value >= 0) return Smi::FromInt(LESS);
5794 if (x_value >= 0) return Smi::FromInt(GREATER);
5795 x_value = -x_value;
5796 y_value = -y_value;
5797 }
5798
5799 // Convert the integers to arrays of their decimal digits.
5800 int x_index = 0;
5801 int y_index = 0;
5802 while (x_value > 0) {
5803 x_elms[x_index++] = x_value % 10;
5804 x_value /= 10;
5805 }
5806 while (y_value > 0) {
5807 y_elms[y_index++] = y_value % 10;
5808 y_value /= 10;
5809 }
5810
5811 // Loop through the arrays of decimal digits finding the first place
5812 // where they differ.
5813 while (--x_index >= 0 && --y_index >= 0) {
5814 int diff = x_elms[x_index] - y_elms[y_index];
5815 if (diff != 0) return Smi::FromInt(diff);
5816 }
5817
5818 // If one array is a suffix of the other array, the longest array is
5819 // the representation of the largest of the Smis in the
5820 // lexicographic ordering.
5821 return Smi::FromInt(x_index - y_index);
5822}
5823
5824
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005825static Object* StringInputBufferCompare(String* x, String* y) {
5826 static StringInputBuffer bufx;
5827 static StringInputBuffer bufy;
5828 bufx.Reset(x);
5829 bufy.Reset(y);
5830 while (bufx.has_more() && bufy.has_more()) {
5831 int d = bufx.GetNext() - bufy.GetNext();
5832 if (d < 0) return Smi::FromInt(LESS);
5833 else if (d > 0) return Smi::FromInt(GREATER);
5834 }
5835
5836 // x is (non-trivial) prefix of y:
5837 if (bufy.has_more()) return Smi::FromInt(LESS);
5838 // y is prefix of x:
5839 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
5840}
5841
5842
5843static Object* FlatStringCompare(String* x, String* y) {
5844 ASSERT(x->IsFlat());
5845 ASSERT(y->IsFlat());
5846 Object* equal_prefix_result = Smi::FromInt(EQUAL);
5847 int prefix_length = x->length();
5848 if (y->length() < prefix_length) {
5849 prefix_length = y->length();
5850 equal_prefix_result = Smi::FromInt(GREATER);
5851 } else if (y->length() > prefix_length) {
5852 equal_prefix_result = Smi::FromInt(LESS);
5853 }
5854 int r;
5855 if (x->IsAsciiRepresentation()) {
5856 Vector<const char> x_chars = x->ToAsciiVector();
5857 if (y->IsAsciiRepresentation()) {
5858 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005859 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005860 } else {
5861 Vector<const uc16> y_chars = y->ToUC16Vector();
5862 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5863 }
5864 } else {
5865 Vector<const uc16> x_chars = x->ToUC16Vector();
5866 if (y->IsAsciiRepresentation()) {
5867 Vector<const char> y_chars = y->ToAsciiVector();
5868 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5869 } else {
5870 Vector<const uc16> y_chars = y->ToUC16Vector();
5871 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5872 }
5873 }
5874 Object* result;
5875 if (r == 0) {
5876 result = equal_prefix_result;
5877 } else {
5878 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
5879 }
5880 ASSERT(result == StringInputBufferCompare(x, y));
5881 return result;
5882}
5883
5884
lrn@chromium.org303ada72010-10-27 09:33:13 +00005885static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005886 NoHandleAllocation ha;
5887 ASSERT(args.length() == 2);
5888
5889 CONVERT_CHECKED(String, x, args[0]);
5890 CONVERT_CHECKED(String, y, args[1]);
5891
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005892 Counters::string_compare_runtime.Increment();
5893
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005894 // A few fast case tests before we flatten.
5895 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005896 if (y->length() == 0) {
5897 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005898 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005899 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005900 return Smi::FromInt(LESS);
5901 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005902
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005903 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005904 if (d < 0) return Smi::FromInt(LESS);
5905 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005906
lrn@chromium.org303ada72010-10-27 09:33:13 +00005907 Object* obj;
5908 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
5909 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5910 }
5911 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
5912 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5913 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005914
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005915 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
5916 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005917}
5918
5919
lrn@chromium.org303ada72010-10-27 09:33:13 +00005920static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921 NoHandleAllocation ha;
5922 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005923 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005924
5925 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005926 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005927}
5928
5929
lrn@chromium.org303ada72010-10-27 09:33:13 +00005930static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005931 NoHandleAllocation ha;
5932 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005933 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005934
5935 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005936 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005937}
5938
5939
lrn@chromium.org303ada72010-10-27 09:33:13 +00005940static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005941 NoHandleAllocation ha;
5942 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005943 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005944
5945 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005946 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005947}
5948
5949
lrn@chromium.org303ada72010-10-27 09:33:13 +00005950static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005951 NoHandleAllocation ha;
5952 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005953 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005954
5955 CONVERT_DOUBLE_CHECKED(x, args[0]);
5956 CONVERT_DOUBLE_CHECKED(y, args[1]);
5957 double result;
5958 if (isinf(x) && isinf(y)) {
5959 // Make sure that the result in case of two infinite arguments
5960 // is a multiple of Pi / 4. The sign of the result is determined
5961 // by the first argument (x) and the sign of the second argument
5962 // determines the multiplier: one or three.
5963 static double kPiDividedBy4 = 0.78539816339744830962;
5964 int multiplier = (x < 0) ? -1 : 1;
5965 if (y < 0) multiplier *= 3;
5966 result = multiplier * kPiDividedBy4;
5967 } else {
5968 result = atan2(x, y);
5969 }
5970 return Heap::AllocateHeapNumber(result);
5971}
5972
5973
lrn@chromium.org303ada72010-10-27 09:33:13 +00005974static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005975 NoHandleAllocation ha;
5976 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005977 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005978
5979 CONVERT_DOUBLE_CHECKED(x, args[0]);
5980 return Heap::NumberFromDouble(ceiling(x));
5981}
5982
5983
lrn@chromium.org303ada72010-10-27 09:33:13 +00005984static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005985 NoHandleAllocation ha;
5986 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005987 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005988
5989 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005990 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005991}
5992
5993
lrn@chromium.org303ada72010-10-27 09:33:13 +00005994static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995 NoHandleAllocation ha;
5996 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005997 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998
5999 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006000 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006001}
6002
6003
lrn@chromium.org303ada72010-10-27 09:33:13 +00006004static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006005 NoHandleAllocation ha;
6006 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006007 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006008
6009 CONVERT_DOUBLE_CHECKED(x, args[0]);
6010 return Heap::NumberFromDouble(floor(x));
6011}
6012
6013
lrn@chromium.org303ada72010-10-27 09:33:13 +00006014static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006015 NoHandleAllocation ha;
6016 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006017 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006018
6019 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006020 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006021}
6022
6023
lrn@chromium.org303ada72010-10-27 09:33:13 +00006024static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006025 NoHandleAllocation ha;
6026 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006027 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006028
6029 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006030
6031 // If the second argument is a smi, it is much faster to call the
6032 // custom powi() function than the generic pow().
6033 if (args[1]->IsSmi()) {
6034 int y = Smi::cast(args[1])->value();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006035 return Heap::NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006036 }
6037
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038 CONVERT_DOUBLE_CHECKED(y, args[1]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006039 return Heap::AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040}
6041
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006042// Fast version of Math.pow if we know that y is not an integer and
6043// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006044static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006045 NoHandleAllocation ha;
6046 ASSERT(args.length() == 2);
6047 CONVERT_DOUBLE_CHECKED(x, args[0]);
6048 CONVERT_DOUBLE_CHECKED(y, args[1]);
6049 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006050 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006051 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006052 return Heap::nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006053 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006054 return Heap::AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006055 }
6056}
6057
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006058
lrn@chromium.org303ada72010-10-27 09:33:13 +00006059static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006060 NoHandleAllocation ha;
6061 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006062 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006063
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006064 if (!args[0]->IsHeapNumber()) {
6065 // Must be smi. Return the argument unchanged for all the other types
6066 // to make fuzz-natives test happy.
6067 return args[0];
6068 }
6069
6070 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6071
6072 double value = number->value();
6073 int exponent = number->get_exponent();
6074 int sign = number->get_sign();
6075
6076 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6077 // should be rounded to 2^30, which is not smi.
6078 if (!sign && exponent <= kSmiValueSize - 3) {
6079 return Smi::FromInt(static_cast<int>(value + 0.5));
6080 }
6081
6082 // If the magnitude is big enough, there's no place for fraction part. If we
6083 // try to add 0.5 to this number, 1.0 will be added instead.
6084 if (exponent >= 52) {
6085 return number;
6086 }
6087
6088 if (sign && value >= -0.5) return Heap::minus_zero_value();
6089
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006090 // Do not call NumberFromDouble() to avoid extra checks.
6091 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006092}
6093
6094
lrn@chromium.org303ada72010-10-27 09:33:13 +00006095static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006096 NoHandleAllocation ha;
6097 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006098 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006099
6100 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006101 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006102}
6103
6104
lrn@chromium.org303ada72010-10-27 09:33:13 +00006105static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006106 NoHandleAllocation ha;
6107 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006108 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006109
6110 CONVERT_DOUBLE_CHECKED(x, args[0]);
6111 return Heap::AllocateHeapNumber(sqrt(x));
6112}
6113
6114
lrn@chromium.org303ada72010-10-27 09:33:13 +00006115static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006116 NoHandleAllocation ha;
6117 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006118 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006119
6120 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006121 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006122}
6123
6124
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006125static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006126 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6127 181, 212, 243, 273, 304, 334};
6128 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6129 182, 213, 244, 274, 305, 335};
6130
6131 year += month / 12;
6132 month %= 12;
6133 if (month < 0) {
6134 year--;
6135 month += 12;
6136 }
6137
6138 ASSERT(month >= 0);
6139 ASSERT(month < 12);
6140
6141 // year_delta is an arbitrary number such that:
6142 // a) year_delta = -1 (mod 400)
6143 // b) year + year_delta > 0 for years in the range defined by
6144 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6145 // Jan 1 1970. This is required so that we don't run into integer
6146 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006147 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006148 // operations.
6149 static const int year_delta = 399999;
6150 static const int base_day = 365 * (1970 + year_delta) +
6151 (1970 + year_delta) / 4 -
6152 (1970 + year_delta) / 100 +
6153 (1970 + year_delta) / 400;
6154
6155 int year1 = year + year_delta;
6156 int day_from_year = 365 * year1 +
6157 year1 / 4 -
6158 year1 / 100 +
6159 year1 / 400 -
6160 base_day;
6161
6162 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006163 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006164 }
6165
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006166 return day_from_year + day_from_month_leap[month] + day - 1;
6167}
6168
6169
lrn@chromium.org303ada72010-10-27 09:33:13 +00006170static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006171 NoHandleAllocation ha;
6172 ASSERT(args.length() == 3);
6173
6174 CONVERT_SMI_CHECKED(year, args[0]);
6175 CONVERT_SMI_CHECKED(month, args[1]);
6176 CONVERT_SMI_CHECKED(date, args[2]);
6177
6178 return Smi::FromInt(MakeDay(year, month, date));
6179}
6180
6181
6182static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6183static const int kDaysIn4Years = 4 * 365 + 1;
6184static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6185static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6186static const int kDays1970to2000 = 30 * 365 + 7;
6187static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6188 kDays1970to2000;
6189static const int kYearsOffset = 400000;
6190
6191static const char kDayInYear[] = {
6192 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6193 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6194 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6195 22, 23, 24, 25, 26, 27, 28,
6196 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6197 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6198 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6199 22, 23, 24, 25, 26, 27, 28, 29, 30,
6200 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6201 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6202 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6203 22, 23, 24, 25, 26, 27, 28, 29, 30,
6204 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6205 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6206 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6207 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6208 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6209 22, 23, 24, 25, 26, 27, 28, 29, 30,
6210 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6211 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6212 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6213 22, 23, 24, 25, 26, 27, 28, 29, 30,
6214 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6215 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6216
6217 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6218 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6219 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6220 22, 23, 24, 25, 26, 27, 28,
6221 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6222 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6223 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6224 22, 23, 24, 25, 26, 27, 28, 29, 30,
6225 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6226 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6227 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6228 22, 23, 24, 25, 26, 27, 28, 29, 30,
6229 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6230 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6231 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6232 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6233 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6234 22, 23, 24, 25, 26, 27, 28, 29, 30,
6235 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6236 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6237 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6238 22, 23, 24, 25, 26, 27, 28, 29, 30,
6239 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6240 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6241
6242 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6243 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6244 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6245 22, 23, 24, 25, 26, 27, 28, 29,
6246 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6247 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6248 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6249 22, 23, 24, 25, 26, 27, 28, 29, 30,
6250 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6251 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6252 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6253 22, 23, 24, 25, 26, 27, 28, 29, 30,
6254 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6255 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6256 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6257 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6258 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6259 22, 23, 24, 25, 26, 27, 28, 29, 30,
6260 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6261 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6262 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6263 22, 23, 24, 25, 26, 27, 28, 29, 30,
6264 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6265 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6266
6267 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6268 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6269 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6270 22, 23, 24, 25, 26, 27, 28,
6271 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6272 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6273 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6274 22, 23, 24, 25, 26, 27, 28, 29, 30,
6275 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6276 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6277 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6278 22, 23, 24, 25, 26, 27, 28, 29, 30,
6279 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6280 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6281 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6282 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6283 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6284 22, 23, 24, 25, 26, 27, 28, 29, 30,
6285 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6286 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6287 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6288 22, 23, 24, 25, 26, 27, 28, 29, 30,
6289 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6290 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6291
6292static const char kMonthInYear[] = {
6293 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,
6294 0, 0, 0, 0, 0, 0,
6295 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,
6296 1, 1, 1,
6297 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,
6298 2, 2, 2, 2, 2, 2,
6299 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,
6300 3, 3, 3, 3, 3,
6301 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,
6302 4, 4, 4, 4, 4, 4,
6303 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,
6304 5, 5, 5, 5, 5,
6305 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,
6306 6, 6, 6, 6, 6, 6,
6307 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,
6308 7, 7, 7, 7, 7, 7,
6309 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,
6310 8, 8, 8, 8, 8,
6311 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,
6312 9, 9, 9, 9, 9, 9,
6313 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6314 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6315 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6316 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6317
6318 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,
6319 0, 0, 0, 0, 0, 0,
6320 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,
6321 1, 1, 1,
6322 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,
6323 2, 2, 2, 2, 2, 2,
6324 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,
6325 3, 3, 3, 3, 3,
6326 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,
6327 4, 4, 4, 4, 4, 4,
6328 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,
6329 5, 5, 5, 5, 5,
6330 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,
6331 6, 6, 6, 6, 6, 6,
6332 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,
6333 7, 7, 7, 7, 7, 7,
6334 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,
6335 8, 8, 8, 8, 8,
6336 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,
6337 9, 9, 9, 9, 9, 9,
6338 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6339 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6340 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6341 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6342
6343 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,
6344 0, 0, 0, 0, 0, 0,
6345 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,
6346 1, 1, 1, 1,
6347 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,
6348 2, 2, 2, 2, 2, 2,
6349 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,
6350 3, 3, 3, 3, 3,
6351 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,
6352 4, 4, 4, 4, 4, 4,
6353 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,
6354 5, 5, 5, 5, 5,
6355 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,
6356 6, 6, 6, 6, 6, 6,
6357 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,
6358 7, 7, 7, 7, 7, 7,
6359 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,
6360 8, 8, 8, 8, 8,
6361 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,
6362 9, 9, 9, 9, 9, 9,
6363 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6364 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6365 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6366 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6367
6368 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,
6369 0, 0, 0, 0, 0, 0,
6370 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,
6371 1, 1, 1,
6372 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,
6373 2, 2, 2, 2, 2, 2,
6374 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,
6375 3, 3, 3, 3, 3,
6376 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,
6377 4, 4, 4, 4, 4, 4,
6378 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,
6379 5, 5, 5, 5, 5,
6380 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,
6381 6, 6, 6, 6, 6, 6,
6382 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,
6383 7, 7, 7, 7, 7, 7,
6384 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,
6385 8, 8, 8, 8, 8,
6386 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,
6387 9, 9, 9, 9, 9, 9,
6388 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6389 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6390 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6391 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6392
6393
6394// This function works for dates from 1970 to 2099.
6395static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006396 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006397#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006398 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006399#endif
6400
6401 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6402 date %= kDaysIn4Years;
6403
6404 month = kMonthInYear[date];
6405 day = kDayInYear[date];
6406
6407 ASSERT(MakeDay(year, month, day) == save_date);
6408}
6409
6410
6411static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006412 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006413#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006414 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006415#endif
6416
6417 date += kDaysOffset;
6418 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6419 date %= kDaysIn400Years;
6420
6421 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6422
6423 date--;
6424 int yd1 = date / kDaysIn100Years;
6425 date %= kDaysIn100Years;
6426 year += 100 * yd1;
6427
6428 date++;
6429 int yd2 = date / kDaysIn4Years;
6430 date %= kDaysIn4Years;
6431 year += 4 * yd2;
6432
6433 date--;
6434 int yd3 = date / 365;
6435 date %= 365;
6436 year += yd3;
6437
6438 bool is_leap = (!yd1 || yd2) && !yd3;
6439
6440 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006441 ASSERT(is_leap || (date >= 0));
6442 ASSERT((date < 365) || (is_leap && (date < 366)));
6443 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6444 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6445 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006446
6447 if (is_leap) {
6448 day = kDayInYear[2*365 + 1 + date];
6449 month = kMonthInYear[2*365 + 1 + date];
6450 } else {
6451 day = kDayInYear[date];
6452 month = kMonthInYear[date];
6453 }
6454
6455 ASSERT(MakeDay(year, month, day) == save_date);
6456}
6457
6458
6459static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006460 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006461 if (date >= 0 && date < 32 * kDaysIn4Years) {
6462 DateYMDFromTimeAfter1970(date, year, month, day);
6463 } else {
6464 DateYMDFromTimeSlow(date, year, month, day);
6465 }
6466}
6467
6468
lrn@chromium.org303ada72010-10-27 09:33:13 +00006469static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006470 NoHandleAllocation ha;
6471 ASSERT(args.length() == 2);
6472
6473 CONVERT_DOUBLE_CHECKED(t, args[0]);
6474 CONVERT_CHECKED(JSArray, res_array, args[1]);
6475
6476 int year, month, day;
6477 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6478
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006479 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6480 FixedArray* elms = FixedArray::cast(res_array->elements());
6481 RUNTIME_ASSERT(elms->length() == 3);
6482
6483 elms->set(0, Smi::FromInt(year));
6484 elms->set(1, Smi::FromInt(month));
6485 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006486
6487 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006488}
6489
6490
lrn@chromium.org303ada72010-10-27 09:33:13 +00006491static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006492 NoHandleAllocation ha;
6493 ASSERT(args.length() == 3);
6494
6495 JSFunction* callee = JSFunction::cast(args[0]);
6496 Object** parameters = reinterpret_cast<Object**>(args[1]);
6497 const int length = Smi::cast(args[2])->value();
6498
lrn@chromium.org303ada72010-10-27 09:33:13 +00006499 Object* result;
6500 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6501 if (!maybe_result->ToObject(&result)) return maybe_result;
6502 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006503 // Allocate the elements if needed.
6504 if (length > 0) {
6505 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006506 Object* obj;
6507 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6508 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6509 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006510
6511 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006512 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6513 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006514 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006515
6516 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006517 for (int i = 0; i < length; i++) {
6518 array->set(i, *--parameters, mode);
6519 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006520 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006521 }
6522 return result;
6523}
6524
6525
lrn@chromium.org303ada72010-10-27 09:33:13 +00006526static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006527 HandleScope scope;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006528 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00006529 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006530 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006531 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006532
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006533 // Allocate global closures in old space and allocate local closures
6534 // in new space. Additionally pretenure closures that are assigned
6535 // directly to properties.
6536 pretenure = pretenure || (context->global_context() == *context);
6537 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006538 Handle<JSFunction> result =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006539 Factory::NewFunctionFromSharedFunctionInfo(shared,
6540 context,
6541 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006542 return *result;
6543}
6544
lrn@chromium.org303ada72010-10-27 09:33:13 +00006545static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006546 HandleScope scope;
6547 ASSERT(args.length() == 2);
6548 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6549 CONVERT_ARG_CHECKED(JSArray, params, 1);
6550
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006551 RUNTIME_ASSERT(params->HasFastElements());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006552 FixedArray* fixed = FixedArray::cast(params->elements());
6553
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006554 int fixed_length = Smi::cast(params->length())->value();
6555 SmartPointer<Object**> param_data(NewArray<Object**>(fixed_length));
6556 for (int i = 0; i < fixed_length; i++) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006557 Handle<Object> val = Handle<Object>(fixed->get(i));
6558 param_data[i] = val.location();
6559 }
6560
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006561 bool exception = false;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006562 Handle<Object> result = Execution::New(
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006563 function, fixed_length, *param_data, &exception);
6564 if (exception) {
6565 return Failure::Exception();
6566 }
6567 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006568 return *result;
6569}
6570
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006571
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006572static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006573 Handle<Object> prototype = Factory::null_value();
6574 if (function->has_instance_prototype()) {
6575 prototype = Handle<Object>(function->instance_prototype());
6576 }
6577 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006578 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006579 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006580 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006581 function->shared()->set_construct_stub(
6582 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006583 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006584 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006585}
6586
6587
lrn@chromium.org303ada72010-10-27 09:33:13 +00006588static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006589 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006590 ASSERT(args.length() == 1);
6591
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006592 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006593
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006594 // If the constructor isn't a proper function we throw a type error.
6595 if (!constructor->IsJSFunction()) {
6596 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6597 Handle<Object> type_error =
6598 Factory::NewTypeError("not_constructor", arguments);
6599 return Top::Throw(*type_error);
6600 }
6601
6602 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006603
6604 // If function should not have prototype, construction is not allowed. In this
6605 // case generated code bailouts here, since function has no initial_map.
6606 if (!function->should_have_prototype()) {
6607 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6608 Handle<Object> type_error =
6609 Factory::NewTypeError("not_constructor", arguments);
6610 return Top::Throw(*type_error);
6611 }
6612
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006613#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006614 // Handle stepping into constructors if step into is active.
6615 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006616 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006617 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006618#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006619
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006620 if (function->has_initial_map()) {
6621 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006622 // The 'Function' function ignores the receiver object when
6623 // called using 'new' and creates a new JSFunction object that
6624 // is returned. The receiver object is only used for error
6625 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006626 // JSFunction. Factory::NewJSObject() should not be used to
6627 // allocate JSFunctions since it does not properly initialize
6628 // the shared part of the function. Since the receiver is
6629 // ignored anyway, we use the global object as the receiver
6630 // instead of a new JSFunction object. This way, errors are
6631 // reported the same way whether or not 'Function' is called
6632 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633 return Top::context()->global();
6634 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006635 }
6636
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006637 // The function should be compiled for the optimization hints to be
6638 // available. We cannot use EnsureCompiled because that forces a
6639 // compilation through the shared function info which makes it
6640 // impossible for us to optimize.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006641 Handle<SharedFunctionInfo> shared(function->shared());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006642 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006643
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006644 if (!function->has_initial_map() &&
6645 shared->IsInobjectSlackTrackingInProgress()) {
6646 // The tracking is already in progress for another function. We can only
6647 // track one initial_map at a time, so we force the completion before the
6648 // function is called as a constructor for the first time.
6649 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006650 }
6651
6652 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006653 Handle<JSObject> result = Factory::NewJSObject(function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006654 // Delay setting the stub if inobject slack tracking is in progress.
6655 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6656 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006657 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006658
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006659 Counters::constructed_objects.Increment();
6660 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006661
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006662 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006663}
6664
6665
lrn@chromium.org303ada72010-10-27 09:33:13 +00006666static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006667 HandleScope scope;
6668 ASSERT(args.length() == 1);
6669
6670 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6671 function->shared()->CompleteInobjectSlackTracking();
6672 TrySettingInlineConstructStub(function);
6673
6674 return Heap::undefined_value();
6675}
6676
6677
lrn@chromium.org303ada72010-10-27 09:33:13 +00006678static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006679 HandleScope scope;
6680 ASSERT(args.length() == 1);
6681
6682 Handle<JSFunction> function = args.at<JSFunction>(0);
6683#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006684 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006685 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006686 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006687 PrintF("]\n");
6688 }
6689#endif
6690
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006691 // Compile the target function. Here we compile using CompileLazyInLoop in
6692 // order to get the optimized version. This helps code like delta-blue
6693 // that calls performance-critical routines through constructors. A
6694 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6695 // direct call. Since the in-loop tracking takes place through CallICs
6696 // this means that things called through constructors are never known to
6697 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006698 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006699 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006700 return Failure::Exception();
6701 }
6702
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006703 // All done. Return the compiled code.
6704 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006705 return function->code();
6706}
6707
6708
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006709static MaybeObject* Runtime_LazyRecompile(Arguments args) {
6710 HandleScope scope;
6711 ASSERT(args.length() == 1);
6712 Handle<JSFunction> function = args.at<JSFunction>(0);
6713 // If the function is not optimizable or debugger is active continue using the
6714 // code from the full compiler.
6715 if (!function->shared()->code()->optimizable() ||
6716 Debug::has_break_points()) {
6717 function->ReplaceCode(function->shared()->code());
6718 return function->code();
6719 }
6720 if (CompileOptimized(function, AstNode::kNoNumber)) {
6721 return function->code();
6722 }
6723 function->ReplaceCode(function->shared()->code());
6724 return Failure::Exception();
6725}
6726
6727
6728static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
6729 HandleScope scope;
6730 ASSERT(args.length() == 1);
6731 RUNTIME_ASSERT(args[0]->IsSmi());
6732 Deoptimizer::BailoutType type =
6733 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
6734 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6735 ASSERT(Heap::IsAllocationAllowed());
6736 int frames = deoptimizer->output_count();
6737
6738 JavaScriptFrameIterator it;
6739 JavaScriptFrame* frame = NULL;
6740 for (int i = 0; i < frames; i++) {
6741 if (i != 0) it.Advance();
6742 frame = it.frame();
6743 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
6744 }
6745 delete deoptimizer;
6746
6747 RUNTIME_ASSERT(frame->function()->IsJSFunction());
6748 Handle<JSFunction> function(JSFunction::cast(frame->function()));
6749 Handle<Object> arguments;
6750 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00006751 if (frame->GetExpression(i) == Heap::arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006752 if (arguments.is_null()) {
6753 // FunctionGetArguments can't throw an exception, so cast away the
6754 // doubt with an assert.
6755 arguments = Handle<Object>(
6756 Accessors::FunctionGetArguments(*function,
6757 NULL)->ToObjectUnchecked());
6758 ASSERT(*arguments != Heap::null_value());
6759 ASSERT(*arguments != Heap::undefined_value());
6760 }
6761 frame->SetExpression(i, *arguments);
6762 }
6763 }
6764
6765 CompilationCache::MarkForLazyOptimizing(function);
6766 if (type == Deoptimizer::EAGER) {
6767 RUNTIME_ASSERT(function->IsOptimized());
6768 } else {
6769 RUNTIME_ASSERT(!function->IsOptimized());
6770 }
6771
6772 // Avoid doing too much work when running with --always-opt and keep
6773 // the optimized code around.
6774 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
6775 return Heap::undefined_value();
6776 }
6777
6778 // Count the number of optimized activations of the function.
6779 int activations = 0;
6780 while (!it.done()) {
6781 JavaScriptFrame* frame = it.frame();
6782 if (frame->is_optimized() && frame->function() == *function) {
6783 activations++;
6784 }
6785 it.Advance();
6786 }
6787
6788 // TODO(kasperl): For now, we cannot support removing the optimized
6789 // code when we have recursive invocations of the same function.
6790 if (activations == 0) {
6791 if (FLAG_trace_deopt) {
6792 PrintF("[removing optimized code for: ");
6793 function->PrintName();
6794 PrintF("]\n");
6795 }
6796 function->ReplaceCode(function->shared()->code());
6797 }
6798 return Heap::undefined_value();
6799}
6800
6801
6802static MaybeObject* Runtime_NotifyOSR(Arguments args) {
6803 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6804 delete deoptimizer;
6805 return Heap::undefined_value();
6806}
6807
6808
6809static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
6810 HandleScope scope;
6811 ASSERT(args.length() == 1);
6812 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6813 if (!function->IsOptimized()) return Heap::undefined_value();
6814
6815 Deoptimizer::DeoptimizeFunction(*function);
6816
6817 return Heap::undefined_value();
6818}
6819
6820
6821static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
6822 HandleScope scope;
6823 ASSERT(args.length() == 1);
6824 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6825
6826 // We're not prepared to handle a function with arguments object.
6827 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
6828
6829 // We have hit a back edge in an unoptimized frame for a function that was
6830 // selected for on-stack replacement. Find the unoptimized code object.
6831 Handle<Code> unoptimized(function->shared()->code());
6832 // Keep track of whether we've succeeded in optimizing.
6833 bool succeeded = unoptimized->optimizable();
6834 if (succeeded) {
6835 // If we are trying to do OSR when there are already optimized
6836 // activations of the function, it means (a) the function is directly or
6837 // indirectly recursive and (b) an optimized invocation has been
6838 // deoptimized so that we are currently in an unoptimized activation.
6839 // Check for optimized activations of this function.
6840 JavaScriptFrameIterator it;
6841 while (succeeded && !it.done()) {
6842 JavaScriptFrame* frame = it.frame();
6843 succeeded = !frame->is_optimized() || frame->function() != *function;
6844 it.Advance();
6845 }
6846 }
6847
6848 int ast_id = AstNode::kNoNumber;
6849 if (succeeded) {
6850 // The top JS function is this one, the PC is somewhere in the
6851 // unoptimized code.
6852 JavaScriptFrameIterator it;
6853 JavaScriptFrame* frame = it.frame();
6854 ASSERT(frame->function() == *function);
6855 ASSERT(frame->code() == *unoptimized);
6856 ASSERT(unoptimized->contains(frame->pc()));
6857
6858 // Use linear search of the unoptimized code's stack check table to find
6859 // the AST id matching the PC.
6860 Address start = unoptimized->instruction_start();
6861 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
6862 Address table_cursor = start + unoptimized->stack_check_table_start();
6863 uint32_t table_length = Memory::uint32_at(table_cursor);
6864 table_cursor += kIntSize;
6865 for (unsigned i = 0; i < table_length; ++i) {
6866 // Table entries are (AST id, pc offset) pairs.
6867 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
6868 if (pc_offset == target_pc_offset) {
6869 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
6870 break;
6871 }
6872 table_cursor += 2 * kIntSize;
6873 }
6874 ASSERT(ast_id != AstNode::kNoNumber);
6875 if (FLAG_trace_osr) {
6876 PrintF("[replacing on-stack at AST id %d in ", ast_id);
6877 function->PrintName();
6878 PrintF("]\n");
6879 }
6880
6881 // Try to compile the optimized code. A true return value from
6882 // CompileOptimized means that compilation succeeded, not necessarily
6883 // that optimization succeeded.
6884 if (CompileOptimized(function, ast_id) && function->IsOptimized()) {
6885 DeoptimizationInputData* data = DeoptimizationInputData::cast(
6886 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006887 if (data->OsrPcOffset()->value() >= 0) {
6888 if (FLAG_trace_osr) {
6889 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006890 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006891 }
6892 ASSERT(data->OsrAstId()->value() == ast_id);
6893 } else {
6894 // We may never generate the desired OSR entry if we emit an
6895 // early deoptimize.
6896 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006897 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006898 } else {
6899 succeeded = false;
6900 }
6901 }
6902
6903 // Revert to the original stack checks in the original unoptimized code.
6904 if (FLAG_trace_osr) {
6905 PrintF("[restoring original stack checks in ");
6906 function->PrintName();
6907 PrintF("]\n");
6908 }
6909 StackCheckStub check_stub;
6910 Handle<Code> check_code = check_stub.GetCode();
6911 Handle<Code> replacement_code(
6912 Builtins::builtin(Builtins::OnStackReplacement));
6913 // Iterate the unoptimized code and revert all the patched stack checks.
6914 for (RelocIterator it(*unoptimized, RelocInfo::kCodeTargetMask);
6915 !it.done();
6916 it.next()) {
6917 RelocInfo* rinfo = it.rinfo();
6918 if (rinfo->target_address() == replacement_code->entry()) {
6919 Deoptimizer::RevertStackCheckCode(rinfo, *check_code);
6920 }
6921 }
6922
6923 // Allow OSR only at nesting level zero again.
6924 unoptimized->set_allow_osr_at_loop_nesting_level(0);
6925
6926 // If the optimization attempt succeeded, return the AST id tagged as a
6927 // smi. This tells the builtin that we need to translate the unoptimized
6928 // frame to an optimized one.
6929 if (succeeded) {
6930 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
6931 return Smi::FromInt(ast_id);
6932 } else {
6933 return Smi::FromInt(-1);
6934 }
6935}
6936
6937
lrn@chromium.org303ada72010-10-27 09:33:13 +00006938static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006939 HandleScope scope;
6940 ASSERT(args.length() == 1);
6941 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6942 return *Execution::GetFunctionDelegate(args.at<Object>(0));
6943}
6944
6945
lrn@chromium.org303ada72010-10-27 09:33:13 +00006946static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006947 HandleScope scope;
6948 ASSERT(args.length() == 1);
6949 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6950 return *Execution::GetConstructorDelegate(args.at<Object>(0));
6951}
6952
6953
lrn@chromium.org303ada72010-10-27 09:33:13 +00006954static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006955 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00006956 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006957
kasper.lund7276f142008-07-30 08:49:36 +00006958 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00006959 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00006960 Object* result;
6961 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
6962 if (!maybe_result->ToObject(&result)) return maybe_result;
6963 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006964
6965 Top::set_context(Context::cast(result));
6966
kasper.lund7276f142008-07-30 08:49:36 +00006967 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006968}
6969
lrn@chromium.org303ada72010-10-27 09:33:13 +00006970
6971MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
6972 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006973 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006974 Object* js_object = object;
6975 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006976 MaybeObject* maybe_js_object = js_object->ToObject();
6977 if (!maybe_js_object->ToObject(&js_object)) {
6978 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
6979 return maybe_js_object;
6980 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006981 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006982 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006983 Handle<Object> result =
6984 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
6985 return Top::Throw(*result);
6986 }
6987 }
6988
lrn@chromium.org303ada72010-10-27 09:33:13 +00006989 Object* result;
6990 { MaybeObject* maybe_result =
6991 Heap::AllocateWithContext(Top::context(),
6992 JSObject::cast(js_object),
6993 is_catch_context);
6994 if (!maybe_result->ToObject(&result)) return maybe_result;
6995 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006996
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006997 Context* context = Context::cast(result);
6998 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006999
kasper.lund7276f142008-07-30 08:49:36 +00007000 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007001}
7002
7003
lrn@chromium.org303ada72010-10-27 09:33:13 +00007004static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007005 NoHandleAllocation ha;
7006 ASSERT(args.length() == 1);
7007 return PushContextHelper(args[0], false);
7008}
7009
7010
lrn@chromium.org303ada72010-10-27 09:33:13 +00007011static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007012 NoHandleAllocation ha;
7013 ASSERT(args.length() == 1);
7014 return PushContextHelper(args[0], true);
7015}
7016
7017
lrn@chromium.org303ada72010-10-27 09:33:13 +00007018static MaybeObject* Runtime_LookupContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007019 HandleScope scope;
7020 ASSERT(args.length() == 2);
7021
7022 CONVERT_ARG_CHECKED(Context, context, 0);
7023 CONVERT_ARG_CHECKED(String, name, 1);
7024
7025 int index;
7026 PropertyAttributes attributes;
7027 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007028 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007029 context->Lookup(name, flags, &index, &attributes);
7030
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007031 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007032 ASSERT(holder->IsJSObject());
7033 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007034 }
7035
7036 // No intermediate context found. Use global object by default.
7037 return Top::context()->global();
7038}
7039
7040
ager@chromium.orga1645e22009-09-09 19:27:10 +00007041// A mechanism to return a pair of Object pointers in registers (if possible).
7042// How this is achieved is calling convention-dependent.
7043// All currently supported x86 compiles uses calling conventions that are cdecl
7044// variants where a 64-bit value is returned in two 32-bit registers
7045// (edx:eax on ia32, r1:r0 on ARM).
7046// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7047// In Win64 calling convention, a struct of two pointers is returned in memory,
7048// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007049#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007050struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007051 MaybeObject* x;
7052 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007053};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007054
lrn@chromium.org303ada72010-10-27 09:33:13 +00007055static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007056 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007057 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7058 // In Win64 they are assigned to a hidden first argument.
7059 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007060}
7061#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007062typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007063static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007064 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007065 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007066}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007067#endif
7068
7069
lrn@chromium.org303ada72010-10-27 09:33:13 +00007070static inline MaybeObject* Unhole(MaybeObject* x,
7071 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007072 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7073 USE(attributes);
7074 return x->IsTheHole() ? Heap::undefined_value() : x;
7075}
7076
7077
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007078static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
7079 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007080 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007081 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007082 JSFunction* context_extension_function =
7083 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007084 // If the holder isn't a context extension object, we just return it
7085 // as the receiver. This allows arguments objects to be used as
7086 // receivers, but only if they are put in the context scope chain
7087 // explicitly via a with-statement.
7088 Object* constructor = holder->map()->constructor();
7089 if (constructor != context_extension_function) return holder;
7090 // Fall back to using the global object as the receiver if the
7091 // property turns out to be a local variable allocated in a context
7092 // extension object - introduced via eval.
7093 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007094}
7095
7096
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007097static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007098 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00007099 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007100
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007101 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00007102 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007103 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007104 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007105 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007106
7107 int index;
7108 PropertyAttributes attributes;
7109 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007110 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007111 context->Lookup(name, flags, &index, &attributes);
7112
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007113 // If the index is non-negative, the slot has been found in a local
7114 // variable or a parameter. Read it from the context object or the
7115 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007116 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007117 // If the "property" we were looking for is a local variable or an
7118 // argument in a context, the receiver is the global object; see
7119 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
7120 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007121 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007122 ? Context::cast(*holder)->get(index)
7123 : JSObject::cast(*holder)->GetElement(index);
7124 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007125 }
7126
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007127 // If the holder is found, we read the property from it.
7128 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007129 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007130 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007131 JSObject* receiver;
7132 if (object->IsGlobalObject()) {
7133 receiver = GlobalObject::cast(object)->global_receiver();
7134 } else if (context->is_exception_holder(*holder)) {
7135 receiver = Top::context()->global()->global_receiver();
7136 } else {
7137 receiver = ComputeReceiverForNonGlobal(object);
7138 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007139 // No need to unhole the value here. This is taken care of by the
7140 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007141 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007142 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007143 }
7144
7145 if (throw_error) {
7146 // The property doesn't exist - throw exception.
7147 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007148 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007149 return MakePair(Top::Throw(*reference_error), NULL);
7150 } else {
7151 // The property doesn't exist - return undefined
7152 return MakePair(Heap::undefined_value(), Heap::undefined_value());
7153 }
7154}
7155
7156
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007157static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007158 return LoadContextSlotHelper(args, true);
7159}
7160
7161
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007162static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007163 return LoadContextSlotHelper(args, false);
7164}
7165
7166
lrn@chromium.org303ada72010-10-27 09:33:13 +00007167static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007168 HandleScope scope;
7169 ASSERT(args.length() == 3);
7170
7171 Handle<Object> value(args[0]);
7172 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007173 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007174
7175 int index;
7176 PropertyAttributes attributes;
7177 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007178 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007179 context->Lookup(name, flags, &index, &attributes);
7180
7181 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007182 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007183 // Ignore if read_only variable.
7184 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007185 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007186 }
7187 } else {
7188 ASSERT((attributes & READ_ONLY) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007189 Handle<JSObject>::cast(holder)->SetElement(index, *value)->
7190 ToObjectUnchecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007191 }
7192 return *value;
7193 }
7194
7195 // Slow case: The property is not in a FixedArray context.
7196 // It is either in an JSObject extension context or it was not found.
7197 Handle<JSObject> context_ext;
7198
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007199 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007200 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007201 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007202 } else {
7203 // The property was not found. It needs to be stored in the global context.
7204 ASSERT(attributes == ABSENT);
7205 attributes = NONE;
7206 context_ext = Handle<JSObject>(Top::context()->global());
7207 }
7208
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007209 // Set the property, but ignore if read_only variable on the context
7210 // extension object itself.
7211 if ((attributes & READ_ONLY) == 0 ||
7212 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007213 Handle<Object> set = SetProperty(context_ext, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007214 if (set.is_null()) {
7215 // Failure::Exception is converted to a null handle in the
7216 // handle-based methods such as SetProperty. We therefore need
7217 // to convert null handles back to exceptions.
7218 ASSERT(Top::has_pending_exception());
7219 return Failure::Exception();
7220 }
7221 }
7222 return *value;
7223}
7224
7225
lrn@chromium.org303ada72010-10-27 09:33:13 +00007226static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007227 HandleScope scope;
7228 ASSERT(args.length() == 1);
7229
7230 return Top::Throw(args[0]);
7231}
7232
7233
lrn@chromium.org303ada72010-10-27 09:33:13 +00007234static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007235 HandleScope scope;
7236 ASSERT(args.length() == 1);
7237
7238 return Top::ReThrow(args[0]);
7239}
7240
7241
lrn@chromium.org303ada72010-10-27 09:33:13 +00007242static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007243 ASSERT_EQ(0, args.length());
7244 return Top::PromoteScheduledException();
7245}
7246
7247
lrn@chromium.org303ada72010-10-27 09:33:13 +00007248static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007249 HandleScope scope;
7250 ASSERT(args.length() == 1);
7251
7252 Handle<Object> name(args[0]);
7253 Handle<Object> reference_error =
7254 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7255 return Top::Throw(*reference_error);
7256}
7257
7258
lrn@chromium.org303ada72010-10-27 09:33:13 +00007259static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007260 NoHandleAllocation na;
7261 return Top::StackOverflow();
7262}
7263
7264
lrn@chromium.org303ada72010-10-27 09:33:13 +00007265static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007266 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007267
7268 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007269 if (StackGuard::IsStackOverflow()) {
7270 return Runtime_StackOverflow(args);
7271 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007272
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007273 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007274}
7275
7276
7277// NOTE: These PrintXXX functions are defined for all builds (not just
7278// DEBUG builds) because we may want to be able to trace function
7279// calls in all modes.
7280static void PrintString(String* str) {
7281 // not uncommon to have empty strings
7282 if (str->length() > 0) {
7283 SmartPointer<char> s =
7284 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7285 PrintF("%s", *s);
7286 }
7287}
7288
7289
7290static void PrintObject(Object* obj) {
7291 if (obj->IsSmi()) {
7292 PrintF("%d", Smi::cast(obj)->value());
7293 } else if (obj->IsString() || obj->IsSymbol()) {
7294 PrintString(String::cast(obj));
7295 } else if (obj->IsNumber()) {
7296 PrintF("%g", obj->Number());
7297 } else if (obj->IsFailure()) {
7298 PrintF("<failure>");
7299 } else if (obj->IsUndefined()) {
7300 PrintF("<undefined>");
7301 } else if (obj->IsNull()) {
7302 PrintF("<null>");
7303 } else if (obj->IsTrue()) {
7304 PrintF("<true>");
7305 } else if (obj->IsFalse()) {
7306 PrintF("<false>");
7307 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007308 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007309 }
7310}
7311
7312
7313static int StackSize() {
7314 int n = 0;
7315 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7316 return n;
7317}
7318
7319
7320static void PrintTransition(Object* result) {
7321 // indentation
7322 { const int nmax = 80;
7323 int n = StackSize();
7324 if (n <= nmax)
7325 PrintF("%4d:%*s", n, n, "");
7326 else
7327 PrintF("%4d:%*s", n, nmax, "...");
7328 }
7329
7330 if (result == NULL) {
7331 // constructor calls
7332 JavaScriptFrameIterator it;
7333 JavaScriptFrame* frame = it.frame();
7334 if (frame->IsConstructor()) PrintF("new ");
7335 // function name
7336 Object* fun = frame->function();
7337 if (fun->IsJSFunction()) {
7338 PrintObject(JSFunction::cast(fun)->shared()->name());
7339 } else {
7340 PrintObject(fun);
7341 }
7342 // function arguments
7343 // (we are intentionally only printing the actually
7344 // supplied parameters, not all parameters required)
7345 PrintF("(this=");
7346 PrintObject(frame->receiver());
7347 const int length = frame->GetProvidedParametersCount();
7348 for (int i = 0; i < length; i++) {
7349 PrintF(", ");
7350 PrintObject(frame->GetParameter(i));
7351 }
7352 PrintF(") {\n");
7353
7354 } else {
7355 // function result
7356 PrintF("} -> ");
7357 PrintObject(result);
7358 PrintF("\n");
7359 }
7360}
7361
7362
lrn@chromium.org303ada72010-10-27 09:33:13 +00007363static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007364 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007365 NoHandleAllocation ha;
7366 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007367 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007368}
7369
7370
lrn@chromium.org303ada72010-10-27 09:33:13 +00007371static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007372 NoHandleAllocation ha;
7373 PrintTransition(args[0]);
7374 return args[0]; // return TOS
7375}
7376
7377
lrn@chromium.org303ada72010-10-27 09:33:13 +00007378static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007379 NoHandleAllocation ha;
7380 ASSERT(args.length() == 1);
7381
7382#ifdef DEBUG
7383 if (args[0]->IsString()) {
7384 // If we have a string, assume it's a code "marker"
7385 // and print some interesting cpu debugging info.
7386 JavaScriptFrameIterator it;
7387 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007388 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7389 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007390 } else {
7391 PrintF("DebugPrint: ");
7392 }
7393 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007394 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007395 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007396 HeapObject::cast(args[0])->map()->Print();
7397 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007398#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007399 // ShortPrint is available in release mode. Print is not.
7400 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007401#endif
7402 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007403 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007404
7405 return args[0]; // return TOS
7406}
7407
7408
lrn@chromium.org303ada72010-10-27 09:33:13 +00007409static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007410 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007411 NoHandleAllocation ha;
7412 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007413 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007414}
7415
7416
lrn@chromium.org303ada72010-10-27 09:33:13 +00007417static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007418 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007419 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420
7421 // According to ECMA-262, section 15.9.1, page 117, the precision of
7422 // the number in a Date object representing a particular instant in
7423 // time is milliseconds. Therefore, we floor the result of getting
7424 // the OS time.
7425 double millis = floor(OS::TimeCurrentMillis());
7426 return Heap::NumberFromDouble(millis);
7427}
7428
7429
lrn@chromium.org303ada72010-10-27 09:33:13 +00007430static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007431 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007432 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007433
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007434 CONVERT_ARG_CHECKED(String, str, 0);
7435 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007436
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007437 CONVERT_ARG_CHECKED(JSArray, output, 1);
7438 RUNTIME_ASSERT(output->HasFastElements());
7439
7440 AssertNoAllocation no_allocation;
7441
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007442 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007443 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7444 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007445 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007446 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007447 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007448 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007449 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7450 }
7451
7452 if (result) {
7453 return *output;
7454 } else {
7455 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007456 }
7457}
7458
7459
lrn@chromium.org303ada72010-10-27 09:33:13 +00007460static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007461 NoHandleAllocation ha;
7462 ASSERT(args.length() == 1);
7463
7464 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007465 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007466 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7467}
7468
7469
lrn@chromium.org303ada72010-10-27 09:33:13 +00007470static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007471 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007472 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007473
7474 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7475}
7476
7477
lrn@chromium.org303ada72010-10-27 09:33:13 +00007478static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007479 NoHandleAllocation ha;
7480 ASSERT(args.length() == 1);
7481
7482 CONVERT_DOUBLE_CHECKED(x, args[0]);
7483 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7484}
7485
7486
lrn@chromium.org303ada72010-10-27 09:33:13 +00007487static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007488 ASSERT(args.length() == 1);
7489 Object* global = args[0];
7490 if (!global->IsJSGlobalObject()) return Heap::null_value();
7491 return JSGlobalObject::cast(global)->global_receiver();
7492}
7493
7494
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007495static MaybeObject* Runtime_ParseJson(Arguments args) {
7496 HandleScope scope;
7497 ASSERT_EQ(1, args.length());
7498 CONVERT_ARG_CHECKED(String, source, 0);
7499
7500 Handle<Object> result = JsonParser::Parse(source);
7501 if (result.is_null()) {
7502 // Syntax error or stack overflow in scanner.
7503 ASSERT(Top::has_pending_exception());
7504 return Failure::Exception();
7505 }
7506 return *result;
7507}
7508
7509
lrn@chromium.org303ada72010-10-27 09:33:13 +00007510static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007511 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007512 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007513 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007514
ager@chromium.org381abbb2009-02-25 13:23:22 +00007515 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007516 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007517 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7518 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007519 true);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007520 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007521 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007522 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007523 return *fun;
7524}
7525
7526
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007527static ObjectPair CompileGlobalEval(Handle<String> source,
7528 Handle<Object> receiver) {
7529 // Deal with a normal eval call with a string argument. Compile it
7530 // and return the compiled function bound in the local context.
7531 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7532 source,
7533 Handle<Context>(Top::context()),
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007534 Top::context()->IsGlobalContext());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007535 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7536 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7537 shared,
7538 Handle<Context>(Top::context()),
7539 NOT_TENURED);
7540 return MakePair(*compiled, *receiver);
7541}
7542
7543
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007544static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
7545 ASSERT(args.length() == 3);
7546 if (!args[0]->IsJSFunction()) {
7547 return MakePair(Top::ThrowIllegalOperation(), NULL);
7548 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007549
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007550 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007551 Handle<JSFunction> callee = args.at<JSFunction>(0);
7552 Handle<Object> receiver; // Will be overwritten.
7553
7554 // Compute the calling context.
7555 Handle<Context> context = Handle<Context>(Top::context());
7556#ifdef DEBUG
7557 // Make sure Top::context() agrees with the old code that traversed
7558 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007559 StackFrameLocator locator;
7560 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007561 ASSERT(Context::cast(frame->context()) == *context);
7562#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007563
7564 // Find where the 'eval' symbol is bound. It is unaliased only if
7565 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007566 int index = -1;
7567 PropertyAttributes attributes = ABSENT;
7568 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007569 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7570 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007571 // Stop search when eval is found or when the global context is
7572 // reached.
7573 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007574 if (context->is_function_context()) {
7575 context = Handle<Context>(Context::cast(context->closure()->context()));
7576 } else {
7577 context = Handle<Context>(context->previous());
7578 }
7579 }
7580
iposva@chromium.org245aa852009-02-10 00:49:54 +00007581 // If eval could not be resolved, it has been deleted and we need to
7582 // throw a reference error.
7583 if (attributes == ABSENT) {
7584 Handle<Object> name = Factory::eval_symbol();
7585 Handle<Object> reference_error =
7586 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007587 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007588 }
7589
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007590 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007591 // 'eval' is not bound in the global context. Just call the function
7592 // with the given arguments. This is not necessarily the global eval.
7593 if (receiver->IsContext()) {
7594 context = Handle<Context>::cast(receiver);
7595 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007596 } else if (receiver->IsJSContextExtensionObject()) {
7597 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007598 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007599 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007600 }
7601
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007602 // 'eval' is bound in the global context, but it may have been overwritten.
7603 // Compare it to the builtin 'GlobalEval' function to make sure.
7604 if (*callee != Top::global_context()->global_eval_fun() ||
7605 !args[1]->IsString()) {
7606 return MakePair(*callee, Top::context()->global()->global_receiver());
7607 }
7608
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007609 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
7610}
7611
7612
7613static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
7614 ASSERT(args.length() == 3);
7615 if (!args[0]->IsJSFunction()) {
7616 return MakePair(Top::ThrowIllegalOperation(), NULL);
7617 }
7618
7619 HandleScope scope;
7620 Handle<JSFunction> callee = args.at<JSFunction>(0);
7621
7622 // 'eval' is bound in the global context, but it may have been overwritten.
7623 // Compare it to the builtin 'GlobalEval' function to make sure.
7624 if (*callee != Top::global_context()->global_eval_fun() ||
7625 !args[1]->IsString()) {
7626 return MakePair(*callee, Top::context()->global()->global_receiver());
7627 }
7628
7629 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007630}
7631
7632
lrn@chromium.org303ada72010-10-27 09:33:13 +00007633static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007634 // This utility adjusts the property attributes for newly created Function
7635 // object ("new Function(...)") by changing the map.
7636 // All it does is changing the prototype property to enumerable
7637 // as specified in ECMA262, 15.3.5.2.
7638 HandleScope scope;
7639 ASSERT(args.length() == 1);
7640 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7641 ASSERT(func->map()->instance_type() ==
7642 Top::function_instance_map()->instance_type());
7643 ASSERT(func->map()->instance_size() ==
7644 Top::function_instance_map()->instance_size());
7645 func->set_map(*Top::function_instance_map());
7646 return *func;
7647}
7648
7649
lrn@chromium.org303ada72010-10-27 09:33:13 +00007650static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007651 // Allocate a block of memory in NewSpace (filled with a filler).
7652 // Use as fallback for allocation in generated code when NewSpace
7653 // is full.
7654 ASSERT(args.length() == 1);
7655 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7656 int size = size_smi->value();
7657 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7658 RUNTIME_ASSERT(size > 0);
7659 static const int kMinFreeNewSpaceAfterGC =
7660 Heap::InitialSemiSpaceSize() * 3/4;
7661 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007662 Object* allocation;
7663 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7664 if (maybe_allocation->ToObject(&allocation)) {
7665 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7666 }
7667 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007668 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007669}
7670
7671
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007672// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007673// array. Returns true if the element was pushed on the stack and
7674// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007675static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007676 ASSERT(args.length() == 2);
7677 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007678 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007679 RUNTIME_ASSERT(array->HasFastElements());
7680 int length = Smi::cast(array->length())->value();
7681 FixedArray* elements = FixedArray::cast(array->elements());
7682 for (int i = 0; i < length; i++) {
7683 if (elements->get(i) == element) return Heap::false_value();
7684 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007685 Object* obj;
7686 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
7687 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7688 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007689 return Heap::true_value();
7690}
7691
7692
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007693/**
7694 * A simple visitor visits every element of Array's.
7695 * The backend storage can be a fixed array for fast elements case,
7696 * or a dictionary for sparse array. Since Dictionary is a subtype
7697 * of FixedArray, the class can be used by both fast and slow cases.
7698 * The second parameter of the constructor, fast_elements, specifies
7699 * whether the storage is a FixedArray or Dictionary.
7700 *
7701 * An index limit is used to deal with the situation that a result array
7702 * length overflows 32-bit non-negative integer.
7703 */
7704class ArrayConcatVisitor {
7705 public:
7706 ArrayConcatVisitor(Handle<FixedArray> storage,
7707 uint32_t index_limit,
7708 bool fast_elements) :
7709 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007710 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007711
7712 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007713 if (i >= index_limit_ - index_offset_) return;
7714 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007715
7716 if (fast_elements_) {
7717 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7718 storage_->set(index, *elm);
7719
7720 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007721 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7722 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007723 Factory::DictionaryAtNumberPut(dict, index, elm);
7724 if (!result.is_identical_to(dict))
7725 storage_ = result;
7726 }
7727 }
7728
7729 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007730 if (index_limit_ - index_offset_ < delta) {
7731 index_offset_ = index_limit_;
7732 } else {
7733 index_offset_ += delta;
7734 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007735 }
7736
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007737 Handle<FixedArray> storage() { return storage_; }
7738
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007739 private:
7740 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007741 // Limit on the accepted indices. Elements with indices larger than the
7742 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007743 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007744 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007745 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007746 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007747};
7748
7749
ager@chromium.org3811b432009-10-28 14:53:37 +00007750template<class ExternalArrayClass, class ElementType>
7751static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7752 bool elements_are_ints,
7753 bool elements_are_guaranteed_smis,
7754 uint32_t range,
7755 ArrayConcatVisitor* visitor) {
7756 Handle<ExternalArrayClass> array(
7757 ExternalArrayClass::cast(receiver->elements()));
7758 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7759
7760 if (visitor != NULL) {
7761 if (elements_are_ints) {
7762 if (elements_are_guaranteed_smis) {
7763 for (uint32_t j = 0; j < len; j++) {
7764 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7765 visitor->visit(j, e);
7766 }
7767 } else {
7768 for (uint32_t j = 0; j < len; j++) {
7769 int64_t val = static_cast<int64_t>(array->get(j));
7770 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7771 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7772 visitor->visit(j, e);
7773 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007774 Handle<Object> e =
7775 Factory::NewNumber(static_cast<ElementType>(val));
ager@chromium.org3811b432009-10-28 14:53:37 +00007776 visitor->visit(j, e);
7777 }
7778 }
7779 }
7780 } else {
7781 for (uint32_t j = 0; j < len; j++) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007782 Handle<Object> e = Factory::NewNumber(array->get(j));
ager@chromium.org3811b432009-10-28 14:53:37 +00007783 visitor->visit(j, e);
7784 }
7785 }
7786 }
7787
7788 return len;
7789}
7790
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007791/**
7792 * A helper function that visits elements of a JSObject. Only elements
7793 * whose index between 0 and range (exclusive) are visited.
7794 *
7795 * If the third parameter, visitor, is not NULL, the visitor is called
7796 * with parameters, 'visitor_index_offset + element index' and the element.
7797 *
7798 * It returns the number of visisted elements.
7799 */
7800static uint32_t IterateElements(Handle<JSObject> receiver,
7801 uint32_t range,
7802 ArrayConcatVisitor* visitor) {
7803 uint32_t num_of_elements = 0;
7804
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007805 switch (receiver->GetElementsKind()) {
7806 case JSObject::FAST_ELEMENTS: {
7807 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
7808 uint32_t len = elements->length();
7809 if (range < len) {
7810 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007811 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007812
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007813 for (uint32_t j = 0; j < len; j++) {
7814 Handle<Object> e(elements->get(j));
7815 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007816 num_of_elements++;
7817 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007818 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007819 }
7820 }
7821 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007822 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007823 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007824 case JSObject::PIXEL_ELEMENTS: {
7825 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
7826 uint32_t len = pixels->length();
7827 if (range < len) {
7828 len = range;
7829 }
7830
7831 for (uint32_t j = 0; j < len; j++) {
7832 num_of_elements++;
7833 if (visitor != NULL) {
7834 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
7835 visitor->visit(j, e);
7836 }
7837 }
7838 break;
7839 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007840 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
7841 num_of_elements =
7842 IterateExternalArrayElements<ExternalByteArray, int8_t>(
7843 receiver, true, true, range, visitor);
7844 break;
7845 }
7846 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7847 num_of_elements =
7848 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
7849 receiver, true, true, range, visitor);
7850 break;
7851 }
7852 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
7853 num_of_elements =
7854 IterateExternalArrayElements<ExternalShortArray, int16_t>(
7855 receiver, true, true, range, visitor);
7856 break;
7857 }
7858 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7859 num_of_elements =
7860 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
7861 receiver, true, true, range, visitor);
7862 break;
7863 }
7864 case JSObject::EXTERNAL_INT_ELEMENTS: {
7865 num_of_elements =
7866 IterateExternalArrayElements<ExternalIntArray, int32_t>(
7867 receiver, true, false, range, visitor);
7868 break;
7869 }
7870 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7871 num_of_elements =
7872 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
7873 receiver, true, false, range, visitor);
7874 break;
7875 }
7876 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
7877 num_of_elements =
7878 IterateExternalArrayElements<ExternalFloatArray, float>(
7879 receiver, false, false, range, visitor);
7880 break;
7881 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007882 case JSObject::DICTIONARY_ELEMENTS: {
7883 Handle<NumberDictionary> dict(receiver->element_dictionary());
7884 uint32_t capacity = dict->Capacity();
7885 for (uint32_t j = 0; j < capacity; j++) {
7886 Handle<Object> k(dict->KeyAt(j));
7887 if (dict->IsKey(*k)) {
7888 ASSERT(k->IsNumber());
7889 uint32_t index = static_cast<uint32_t>(k->Number());
7890 if (index < range) {
7891 num_of_elements++;
7892 if (visitor) {
7893 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
7894 }
7895 }
7896 }
7897 }
7898 break;
7899 }
7900 default:
7901 UNREACHABLE();
7902 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007903 }
7904
7905 return num_of_elements;
7906}
7907
7908
7909/**
7910 * A helper function that visits elements of an Array object, and elements
7911 * on its prototypes.
7912 *
7913 * Elements on prototypes are visited first, and only elements whose indices
7914 * less than Array length are visited.
7915 *
7916 * If a ArrayConcatVisitor object is given, the visitor is called with
7917 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007918 *
7919 * The returned number of elements is an upper bound on the actual number
7920 * of elements added. If the same element occurs in more than one object
7921 * in the array's prototype chain, it will be counted more than once, but
7922 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007923 */
7924static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
7925 ArrayConcatVisitor* visitor) {
7926 uint32_t range = static_cast<uint32_t>(array->length()->Number());
7927 Handle<Object> obj = array;
7928
7929 static const int kEstimatedPrototypes = 3;
7930 List< Handle<JSObject> > objects(kEstimatedPrototypes);
7931
7932 // Visit prototype first. If an element on the prototype is shadowed by
7933 // the inheritor using the same index, the ArrayConcatVisitor visits
7934 // the prototype element before the shadowing element.
7935 // The visitor can simply overwrite the old value by new value using
7936 // the same index. This follows Array::concat semantics.
7937 while (!obj->IsNull()) {
7938 objects.Add(Handle<JSObject>::cast(obj));
7939 obj = Handle<Object>(obj->GetPrototype());
7940 }
7941
7942 uint32_t nof_elements = 0;
7943 for (int i = objects.length() - 1; i >= 0; i--) {
7944 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007945 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007946 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007947
7948 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
7949 nof_elements = JSObject::kMaxElementCount;
7950 } else {
7951 nof_elements += encountered_elements;
7952 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007953 }
7954
7955 return nof_elements;
7956}
7957
7958
7959/**
7960 * A helper function of Runtime_ArrayConcat.
7961 *
7962 * The first argument is an Array of arrays and objects. It is the
7963 * same as the arguments array of Array::concat JS function.
7964 *
7965 * If an argument is an Array object, the function visits array
7966 * elements. If an argument is not an Array object, the function
7967 * visits the object as if it is an one-element array.
7968 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007969 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007970 * non-negative number is used as new length. For example, if one
7971 * array length is 2^32 - 1, second array length is 1, the
7972 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007973 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
7974 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007975 */
7976static uint32_t IterateArguments(Handle<JSArray> arguments,
7977 ArrayConcatVisitor* visitor) {
7978 uint32_t visited_elements = 0;
7979 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7980
7981 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007982 Object *element;
7983 MaybeObject* maybe_element = arguments->GetElement(i);
7984 // This if() is not expected to fail, but we have the check in the
7985 // interest of hardening the runtime calls.
7986 if (maybe_element->ToObject(&element)) {
7987 Handle<Object> obj(element);
7988 if (obj->IsJSArray()) {
7989 Handle<JSArray> array = Handle<JSArray>::cast(obj);
7990 uint32_t len = static_cast<uint32_t>(array->length()->Number());
7991 uint32_t nof_elements =
7992 IterateArrayAndPrototypeElements(array, visitor);
7993 // Total elements of array and its prototype chain can be more than
7994 // the array length, but ArrayConcat can only concatenate at most
7995 // the array length number of elements. We use the length as an estimate
7996 // for the actual number of elements added.
7997 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
7998 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
7999 visited_elements = JSArray::kMaxElementCount;
8000 } else {
8001 visited_elements += added_elements;
8002 }
8003 if (visitor) visitor->increase_index_offset(len);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008004 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008005 if (visitor) {
8006 visitor->visit(0, obj);
8007 visitor->increase_index_offset(1);
8008 }
8009 if (visited_elements < JSArray::kMaxElementCount) {
8010 visited_elements++;
8011 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008012 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008013 }
8014 }
8015 return visited_elements;
8016}
8017
8018
8019/**
8020 * Array::concat implementation.
8021 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008022 * TODO(lrn): Fix non-compliance for very large concatenations and update to
8023 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008024 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00008025static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008026 ASSERT(args.length() == 1);
8027 HandleScope handle_scope;
8028
8029 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
8030 Handle<JSArray> arguments(arg_arrays);
8031
8032 // Pass 1: estimate the number of elements of the result
8033 // (it could be more than real numbers if prototype has elements).
8034 uint32_t result_length = 0;
8035 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8036
8037 { AssertNoAllocation nogc;
8038 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008039 Object* obj;
8040 MaybeObject* maybe_object = arguments->GetElement(i);
8041 // This if() is not expected to fail, but we have the check in the
8042 // interest of hardening the runtime calls.
8043 if (maybe_object->ToObject(&obj)) {
8044 uint32_t length_estimate;
8045 if (obj->IsJSArray()) {
8046 length_estimate =
8047 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
8048 } else {
8049 length_estimate = 1;
8050 }
8051 if (JSObject::kMaxElementCount - result_length < length_estimate) {
8052 result_length = JSObject::kMaxElementCount;
8053 break;
8054 }
8055 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008056 }
8057 }
8058 }
8059
8060 // Allocate an empty array, will set length and content later.
8061 Handle<JSArray> result = Factory::NewJSArray(0);
8062
8063 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
8064 // If estimated number of elements is more than half of length, a
8065 // fixed array (fast case) is more time and space-efficient than a
8066 // dictionary.
8067 bool fast_case = (estimate_nof_elements * 2) >= result_length;
8068
8069 Handle<FixedArray> storage;
8070 if (fast_case) {
8071 // The backing storage array must have non-existing elements to
8072 // preserve holes across concat operations.
8073 storage = Factory::NewFixedArrayWithHoles(result_length);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008074 Handle<Map> fast_map =
8075 Factory::GetFastElementsMap(Handle<Map>(result->map()));
8076 result->set_map(*fast_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008077 } else {
8078 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8079 uint32_t at_least_space_for = estimate_nof_elements +
8080 (estimate_nof_elements >> 2);
8081 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008082 Factory::NewNumberDictionary(at_least_space_for));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008083 Handle<Map> slow_map =
8084 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
8085 result->set_map(*slow_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008086 }
8087
8088 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
8089
8090 ArrayConcatVisitor visitor(storage, result_length, fast_case);
8091
8092 IterateArguments(arguments, &visitor);
8093
8094 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008095 // Please note the storage might have changed in the visitor.
8096 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008097
8098 return *result;
8099}
8100
8101
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008102// This will not allocate (flatten the string), but it may run
8103// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008104static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008105 NoHandleAllocation ha;
8106 ASSERT(args.length() == 1);
8107
8108 CONVERT_CHECKED(String, string, args[0]);
8109 StringInputBuffer buffer(string);
8110 while (buffer.has_more()) {
8111 uint16_t character = buffer.GetNext();
8112 PrintF("%c", character);
8113 }
8114 return string;
8115}
8116
ager@chromium.org5ec48922009-05-05 07:25:34 +00008117// Moves all own elements of an object, that are below a limit, to positions
8118// starting at zero. All undefined values are placed after non-undefined values,
8119// and are followed by non-existing element. Does not change the length
8120// property.
8121// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008122static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008123 ASSERT(args.length() == 2);
8124 CONVERT_CHECKED(JSObject, object, args[0]);
8125 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8126 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008127}
8128
8129
8130// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00008131static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008132 ASSERT(args.length() == 2);
8133 CONVERT_CHECKED(JSArray, from, args[0]);
8134 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008135 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008136 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008137 if (new_elements->map() == Heap::fixed_array_map() ||
8138 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008139 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008140 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008141 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008142 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008143 Object* new_map;
8144 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008145 to->set_map(Map::cast(new_map));
8146 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008147 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008148 Object* obj;
8149 { MaybeObject* maybe_obj = from->ResetElements();
8150 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8151 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008152 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008153 return to;
8154}
8155
8156
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008157// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00008158static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008159 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008160 CONVERT_CHECKED(JSObject, object, args[0]);
8161 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008162 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008163 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008164 } else if (object->IsJSArray()) {
8165 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008166 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008167 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008168 }
8169}
8170
8171
lrn@chromium.org303ada72010-10-27 09:33:13 +00008172static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008173 HandleScope handle_scope;
8174
8175 ASSERT_EQ(3, args.length());
8176
ager@chromium.orgac091b72010-05-05 07:34:42 +00008177 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008178 Handle<Object> key1 = args.at<Object>(1);
8179 Handle<Object> key2 = args.at<Object>(2);
8180
8181 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008182 if (!key1->ToArrayIndex(&index1)
8183 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00008184 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008185 }
8186
ager@chromium.orgac091b72010-05-05 07:34:42 +00008187 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8188 Handle<Object> tmp1 = GetElement(jsobject, index1);
8189 Handle<Object> tmp2 = GetElement(jsobject, index2);
8190
8191 SetElement(jsobject, index1, tmp2);
8192 SetElement(jsobject, index2, tmp1);
8193
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008194 return Heap::undefined_value();
8195}
8196
8197
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008198// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008199// might have elements. Can either return keys (positive integers) or
8200// intervals (pair of a negative integer (-start-1) followed by a
8201// positive (length)) or undefined values.
8202// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008203static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008204 ASSERT(args.length() == 2);
8205 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008206 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008207 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008208 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008209 // Create an array and get all the keys into it, then remove all the
8210 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008211 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008212 int keys_length = keys->length();
8213 for (int i = 0; i < keys_length; i++) {
8214 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008215 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008216 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008217 // Zap invalid keys.
8218 keys->set_undefined(i);
8219 }
8220 }
8221 return *Factory::NewJSArrayWithElements(keys);
8222 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008223 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008224 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8225 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008226 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008227 uint32_t actual_length =
8228 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008229 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008230 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00008231 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008232 single_interval->set(1, *length_object);
8233 return *Factory::NewJSArrayWithElements(single_interval);
8234 }
8235}
8236
8237
8238// DefineAccessor takes an optional final argument which is the
8239// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8240// to the way accessors are implemented, it is set for both the getter
8241// and setter on the first call to DefineAccessor and ignored on
8242// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008243static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008244 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8245 // Compute attributes.
8246 PropertyAttributes attributes = NONE;
8247 if (args.length() == 5) {
8248 CONVERT_CHECKED(Smi, attrs, args[4]);
8249 int value = attrs->value();
8250 // Only attribute bits should be set.
8251 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8252 attributes = static_cast<PropertyAttributes>(value);
8253 }
8254
8255 CONVERT_CHECKED(JSObject, obj, args[0]);
8256 CONVERT_CHECKED(String, name, args[1]);
8257 CONVERT_CHECKED(Smi, flag, args[2]);
8258 CONVERT_CHECKED(JSFunction, fun, args[3]);
8259 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8260}
8261
8262
lrn@chromium.org303ada72010-10-27 09:33:13 +00008263static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008264 ASSERT(args.length() == 3);
8265 CONVERT_CHECKED(JSObject, obj, args[0]);
8266 CONVERT_CHECKED(String, name, args[1]);
8267 CONVERT_CHECKED(Smi, flag, args[2]);
8268 return obj->LookupAccessor(name, flag->value() == 0);
8269}
8270
8271
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008272#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00008273static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008274 ASSERT(args.length() == 0);
8275 return Execution::DebugBreakHelper();
8276}
8277
8278
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008279// Helper functions for wrapping and unwrapping stack frame ids.
8280static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008281 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008282 return Smi::FromInt(id >> 2);
8283}
8284
8285
8286static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8287 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8288}
8289
8290
8291// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00008292// args[0]: debug event listener function to set or null or undefined for
8293// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008294// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00008295static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008296 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008297 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8298 args[0]->IsUndefined() ||
8299 args[0]->IsNull());
8300 Handle<Object> callback = args.at<Object>(0);
8301 Handle<Object> data = args.at<Object>(1);
8302 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008303
8304 return Heap::undefined_value();
8305}
8306
8307
lrn@chromium.org303ada72010-10-27 09:33:13 +00008308static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008309 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008310 StackGuard::DebugBreak();
8311 return Heap::undefined_value();
8312}
8313
8314
lrn@chromium.org303ada72010-10-27 09:33:13 +00008315static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8316 LookupResult* result,
8317 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008318 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008319 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008320 case NORMAL:
8321 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008322 if (value->IsTheHole()) {
8323 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008324 }
8325 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008326 case FIELD:
8327 value =
8328 JSObject::cast(
8329 result->holder())->FastPropertyAt(result->GetFieldIndex());
8330 if (value->IsTheHole()) {
8331 return Heap::undefined_value();
8332 }
8333 return value;
8334 case CONSTANT_FUNCTION:
8335 return result->GetConstantFunction();
8336 case CALLBACKS: {
8337 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008338 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008339 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008340 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008341 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008342 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008343 ASSERT(maybe_value->IsException());
8344 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008345 Top::clear_pending_exception();
8346 if (caught_exception != NULL) {
8347 *caught_exception = true;
8348 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008349 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008350 }
8351 return value;
8352 } else {
8353 return Heap::undefined_value();
8354 }
8355 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008356 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008357 case MAP_TRANSITION:
8358 case CONSTANT_TRANSITION:
8359 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008360 return Heap::undefined_value();
8361 default:
8362 UNREACHABLE();
8363 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008364 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008365 return Heap::undefined_value();
8366}
8367
8368
ager@chromium.org32912102009-01-16 10:38:43 +00008369// Get debugger related details for an object property.
8370// args[0]: object holding property
8371// args[1]: name of the property
8372//
8373// The array returned contains the following information:
8374// 0: Property value
8375// 1: Property details
8376// 2: Property value is exception
8377// 3: Getter function if defined
8378// 4: Setter function if defined
8379// Items 2-4 are only filled if the property has either a getter or a setter
8380// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008381static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008382 HandleScope scope;
8383
8384 ASSERT(args.length() == 2);
8385
8386 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8387 CONVERT_ARG_CHECKED(String, name, 1);
8388
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008389 // Make sure to set the current context to the context before the debugger was
8390 // entered (if the debugger is entered). The reason for switching context here
8391 // is that for some property lookups (accessors and interceptors) callbacks
8392 // into the embedding application can occour, and the embedding application
8393 // could have the assumption that its own global context is the current
8394 // context and not some internal debugger context.
8395 SaveContext save;
8396 if (Debug::InDebugger()) {
8397 Top::set_context(*Debug::debugger_entry()->GetContext());
8398 }
8399
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008400 // Skip the global proxy as it has no properties and always delegates to the
8401 // real global object.
8402 if (obj->IsJSGlobalProxy()) {
8403 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8404 }
8405
8406
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008407 // Check if the name is trivially convertible to an index and get the element
8408 // if so.
8409 uint32_t index;
8410 if (name->AsArrayIndex(&index)) {
8411 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008412 Object* element_or_char;
8413 { MaybeObject* maybe_element_or_char =
8414 Runtime::GetElementOrCharAt(obj, index);
8415 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8416 return maybe_element_or_char;
8417 }
8418 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008419 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008420 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8421 return *Factory::NewJSArrayWithElements(details);
8422 }
8423
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008424 // Find the number of objects making up this.
8425 int length = LocalPrototypeChainLength(*obj);
8426
8427 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008428 Handle<JSObject> jsproto = obj;
8429 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008430 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008431 jsproto->LocalLookup(*name, &result);
8432 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008433 // LookupResult is not GC safe as it holds raw object pointers.
8434 // GC can happen later in this code so put the required fields into
8435 // local variables using handles when required for later use.
8436 PropertyType result_type = result.type();
8437 Handle<Object> result_callback_obj;
8438 if (result_type == CALLBACKS) {
8439 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8440 }
8441 Smi* property_details = result.GetPropertyDetails().AsSmi();
8442 // DebugLookupResultValue can cause GC so details from LookupResult needs
8443 // to be copied to handles before this.
8444 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008445 Object* raw_value;
8446 { MaybeObject* maybe_raw_value =
8447 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8448 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8449 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008450 Handle<Object> value(raw_value);
8451
8452 // If the callback object is a fixed array then it contains JavaScript
8453 // getter and/or setter.
8454 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8455 result_callback_obj->IsFixedArray();
8456 Handle<FixedArray> details =
8457 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8458 details->set(0, *value);
8459 details->set(1, property_details);
8460 if (hasJavaScriptAccessors) {
8461 details->set(2,
8462 caught_exception ? Heap::true_value()
8463 : Heap::false_value());
8464 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8465 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8466 }
8467
8468 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008469 }
8470 if (i < length - 1) {
8471 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8472 }
8473 }
8474
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008475 return Heap::undefined_value();
8476}
8477
8478
lrn@chromium.org303ada72010-10-27 09:33:13 +00008479static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008480 HandleScope scope;
8481
8482 ASSERT(args.length() == 2);
8483
8484 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8485 CONVERT_ARG_CHECKED(String, name, 1);
8486
8487 LookupResult result;
8488 obj->Lookup(*name, &result);
8489 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008490 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008491 }
8492 return Heap::undefined_value();
8493}
8494
8495
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008496// Return the property type calculated from the property details.
8497// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008498static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008499 ASSERT(args.length() == 1);
8500 CONVERT_CHECKED(Smi, details, args[0]);
8501 PropertyType type = PropertyDetails(details).type();
8502 return Smi::FromInt(static_cast<int>(type));
8503}
8504
8505
8506// Return the property attribute calculated from the property details.
8507// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008508static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008509 ASSERT(args.length() == 1);
8510 CONVERT_CHECKED(Smi, details, args[0]);
8511 PropertyAttributes attributes = PropertyDetails(details).attributes();
8512 return Smi::FromInt(static_cast<int>(attributes));
8513}
8514
8515
8516// Return the property insertion index calculated from the property details.
8517// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008518static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008519 ASSERT(args.length() == 1);
8520 CONVERT_CHECKED(Smi, details, args[0]);
8521 int index = PropertyDetails(details).index();
8522 return Smi::FromInt(index);
8523}
8524
8525
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008526// Return property value from named interceptor.
8527// args[0]: object
8528// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00008529static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008530 HandleScope scope;
8531 ASSERT(args.length() == 2);
8532 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8533 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8534 CONVERT_ARG_CHECKED(String, name, 1);
8535
8536 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008537 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008538}
8539
8540
8541// Return element value from indexed interceptor.
8542// args[0]: object
8543// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00008544static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8545 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008546 HandleScope scope;
8547 ASSERT(args.length() == 2);
8548 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8549 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8550 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8551
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008552 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008553}
8554
8555
lrn@chromium.org303ada72010-10-27 09:33:13 +00008556static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008557 ASSERT(args.length() >= 1);
8558 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008559 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008560 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008561 return Top::Throw(Heap::illegal_execution_state_symbol());
8562 }
8563
8564 return Heap::true_value();
8565}
8566
8567
lrn@chromium.org303ada72010-10-27 09:33:13 +00008568static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008569 HandleScope scope;
8570 ASSERT(args.length() == 1);
8571
8572 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008573 Object* result;
8574 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8575 if (!maybe_result->ToObject(&result)) return maybe_result;
8576 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008577
8578 // Count all frames which are relevant to debugging stack trace.
8579 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008580 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008581 if (id == StackFrame::NO_ID) {
8582 // If there is no JavaScript stack frame count is 0.
8583 return Smi::FromInt(0);
8584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008585 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8586 return Smi::FromInt(n);
8587}
8588
8589
8590static const int kFrameDetailsFrameIdIndex = 0;
8591static const int kFrameDetailsReceiverIndex = 1;
8592static const int kFrameDetailsFunctionIndex = 2;
8593static const int kFrameDetailsArgumentCountIndex = 3;
8594static const int kFrameDetailsLocalCountIndex = 4;
8595static const int kFrameDetailsSourcePositionIndex = 5;
8596static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008597static const int kFrameDetailsAtReturnIndex = 7;
8598static const int kFrameDetailsDebuggerFrameIndex = 8;
8599static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008600
8601// Return an array with frame details
8602// args[0]: number: break id
8603// args[1]: number: frame index
8604//
8605// The array returned contains the following information:
8606// 0: Frame id
8607// 1: Receiver
8608// 2: Function
8609// 3: Argument count
8610// 4: Local count
8611// 5: Source position
8612// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008613// 7: Is at return
8614// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008615// Arguments name, value
8616// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008617// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00008618static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008619 HandleScope scope;
8620 ASSERT(args.length() == 2);
8621
8622 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008623 Object* check;
8624 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8625 if (!maybe_check->ToObject(&check)) return maybe_check;
8626 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008627 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8628
8629 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008630 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008631 if (id == StackFrame::NO_ID) {
8632 // If there are no JavaScript stack frames return undefined.
8633 return Heap::undefined_value();
8634 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008635 int count = 0;
8636 JavaScriptFrameIterator it(id);
8637 for (; !it.done(); it.Advance()) {
8638 if (count == index) break;
8639 count++;
8640 }
8641 if (it.done()) return Heap::undefined_value();
8642
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008643 bool is_optimized_frame =
8644 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
8645
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008646 // Traverse the saved contexts chain to find the active context for the
8647 // selected frame.
8648 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008649 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008650 save = save->prev();
8651 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008652 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008653
8654 // Get the frame id.
8655 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8656
8657 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008658 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008659
8660 // Check for constructor frame.
8661 bool constructor = it.frame()->IsConstructor();
8662
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008663 // Get scope info and read from it for local variable information.
8664 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008665 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008666 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008667
8668 // Get the context.
8669 Handle<Context> context(Context::cast(it.frame()->context()));
8670
8671 // Get the locals names and values into a temporary array.
8672 //
8673 // TODO(1240907): Hide compiler-introduced stack variables
8674 // (e.g. .result)? For users of the debugger, they will probably be
8675 // confusing.
8676 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008677
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008678 // Fill in the names of the locals.
8679 for (int i = 0; i < info.NumberOfLocals(); i++) {
8680 locals->set(i * 2, *info.LocalName(i));
8681 }
8682
8683 // Fill in the values of the locals.
8684 for (int i = 0; i < info.NumberOfLocals(); i++) {
8685 if (is_optimized_frame) {
8686 // If we are inspecting an optimized frame use undefined as the
8687 // value for all locals.
8688 //
8689 // TODO(3141533): We should be able to get the correct values
8690 // for locals in optimized frames.
8691 locals->set(i * 2 + 1, Heap::undefined_value());
8692 } else if (i < info.number_of_stack_slots()) {
8693 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008694 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8695 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008696 // Traverse the context chain to the function context as all local
8697 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008698 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008699 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008700 context = Handle<Context>(context->previous());
8701 }
8702 ASSERT(context->is_function_context());
8703 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00008704 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008705 }
8706 }
8707
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008708 // Check whether this frame is positioned at return. If not top
8709 // frame or if the frame is optimized it cannot be at a return.
8710 bool at_return = false;
8711 if (!is_optimized_frame && index == 0) {
8712 at_return = Debug::IsBreakAtReturn(it.frame());
8713 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008714
8715 // If positioned just before return find the value to be returned and add it
8716 // to the frame information.
8717 Handle<Object> return_value = Factory::undefined_value();
8718 if (at_return) {
8719 StackFrameIterator it2;
8720 Address internal_frame_sp = NULL;
8721 while (!it2.done()) {
8722 if (it2.frame()->is_internal()) {
8723 internal_frame_sp = it2.frame()->sp();
8724 } else {
8725 if (it2.frame()->is_java_script()) {
8726 if (it2.frame()->id() == it.frame()->id()) {
8727 // The internal frame just before the JavaScript frame contains the
8728 // value to return on top. A debug break at return will create an
8729 // internal frame to store the return value (eax/rax/r0) before
8730 // entering the debug break exit frame.
8731 if (internal_frame_sp != NULL) {
8732 return_value =
8733 Handle<Object>(Memory::Object_at(internal_frame_sp));
8734 break;
8735 }
8736 }
8737 }
8738
8739 // Indicate that the previous frame was not an internal frame.
8740 internal_frame_sp = NULL;
8741 }
8742 it2.Advance();
8743 }
8744 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008745
8746 // Now advance to the arguments adapter frame (if any). It contains all
8747 // the provided parameters whereas the function frame always have the number
8748 // of arguments matching the functions parameters. The rest of the
8749 // information (except for what is collected above) is the same.
8750 it.AdvanceToArgumentsFrame();
8751
8752 // Find the number of arguments to fill. At least fill the number of
8753 // parameters for the function and fill more if more parameters are provided.
8754 int argument_count = info.number_of_parameters();
8755 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8756 argument_count = it.frame()->GetProvidedParametersCount();
8757 }
8758
8759 // Calculate the size of the result.
8760 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008761 2 * (argument_count + info.NumberOfLocals()) +
8762 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008763 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8764
8765 // Add the frame id.
8766 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8767
8768 // Add the function (same as in function frame).
8769 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8770
8771 // Add the arguments count.
8772 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8773
8774 // Add the locals count
8775 details->set(kFrameDetailsLocalCountIndex,
8776 Smi::FromInt(info.NumberOfLocals()));
8777
8778 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00008779 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008780 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8781 } else {
8782 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
8783 }
8784
8785 // Add the constructor information.
8786 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
8787
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008788 // Add the at return information.
8789 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
8790
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008791 // Add information on whether this frame is invoked in the debugger context.
8792 details->set(kFrameDetailsDebuggerFrameIndex,
8793 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
8794
8795 // Fill the dynamic part.
8796 int details_index = kFrameDetailsFirstDynamicIndex;
8797
8798 // Add arguments name and value.
8799 for (int i = 0; i < argument_count; i++) {
8800 // Name of the argument.
8801 if (i < info.number_of_parameters()) {
8802 details->set(details_index++, *info.parameter_name(i));
8803 } else {
8804 details->set(details_index++, Heap::undefined_value());
8805 }
8806
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008807 // Parameter value. If we are inspecting an optimized frame, use
8808 // undefined as the value.
8809 //
8810 // TODO(3141533): We should be able to get the actual parameter
8811 // value for optimized frames.
8812 if (!is_optimized_frame &&
8813 (i < it.frame()->GetProvidedParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008814 details->set(details_index++, it.frame()->GetParameter(i));
8815 } else {
8816 details->set(details_index++, Heap::undefined_value());
8817 }
8818 }
8819
8820 // Add locals name and value from the temporary copy from the function frame.
8821 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
8822 details->set(details_index++, locals->get(i));
8823 }
8824
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008825 // Add the value being returned.
8826 if (at_return) {
8827 details->set(details_index++, *return_value);
8828 }
8829
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008830 // Add the receiver (same as in function frame).
8831 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
8832 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
8833 Handle<Object> receiver(it.frame()->receiver());
8834 if (!receiver->IsJSObject()) {
8835 // If the receiver is NOT a JSObject we have hit an optimization
8836 // where a value object is not converted into a wrapped JS objects.
8837 // To hide this optimization from the debugger, we wrap the receiver
8838 // by creating correct wrapper object based on the calling frame's
8839 // global context.
8840 it.Advance();
8841 Handle<Context> calling_frames_global_context(
8842 Context::cast(Context::cast(it.frame()->context())->global_context()));
8843 receiver = Factory::ToObject(receiver, calling_frames_global_context);
8844 }
8845 details->set(kFrameDetailsReceiverIndex, *receiver);
8846
8847 ASSERT_EQ(details_size, details_index);
8848 return *Factory::NewJSArrayWithElements(details);
8849}
8850
8851
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008852// Copy all the context locals into an object used to materialize a scope.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008853static void CopyContextLocalsToScopeObject(
8854 Handle<SerializedScopeInfo> serialized_scope_info,
8855 ScopeInfo<>& scope_info,
8856 Handle<Context> context,
8857 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008858 // Fill all context locals to the context extension.
8859 for (int i = Context::MIN_CONTEXT_SLOTS;
8860 i < scope_info.number_of_context_slots();
8861 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00008862 int context_index = serialized_scope_info->ContextSlotIndex(
8863 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008864
8865 // Don't include the arguments shadow (.arguments) context variable.
8866 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
8867 SetProperty(scope_object,
8868 scope_info.context_slot_name(i),
8869 Handle<Object>(context->get(context_index)), NONE);
8870 }
8871 }
8872}
8873
8874
8875// Create a plain JSObject which materializes the local scope for the specified
8876// frame.
8877static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
8878 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008879 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008880 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8881 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008882
8883 // Allocate and initialize a JSObject with all the arguments, stack locals
8884 // heap locals and extension properties of the debugged function.
8885 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
8886
8887 // First fill all parameters.
8888 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8889 SetProperty(local_scope,
8890 scope_info.parameter_name(i),
8891 Handle<Object>(frame->GetParameter(i)), NONE);
8892 }
8893
8894 // Second fill all stack locals.
8895 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
8896 SetProperty(local_scope,
8897 scope_info.stack_slot_name(i),
8898 Handle<Object>(frame->GetExpression(i)), NONE);
8899 }
8900
8901 // Third fill all context locals.
8902 Handle<Context> frame_context(Context::cast(frame->context()));
8903 Handle<Context> function_context(frame_context->fcontext());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008904 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008905 function_context, local_scope);
8906
8907 // Finally copy any properties from the function context extension. This will
8908 // be variables introduced by eval.
8909 if (function_context->closure() == *function) {
8910 if (function_context->has_extension() &&
8911 !function_context->IsGlobalContext()) {
8912 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008913 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008914 for (int i = 0; i < keys->length(); i++) {
8915 // Names of variables introduced by eval are strings.
8916 ASSERT(keys->get(i)->IsString());
8917 Handle<String> key(String::cast(keys->get(i)));
8918 SetProperty(local_scope, key, GetProperty(ext, key), NONE);
8919 }
8920 }
8921 }
8922 return local_scope;
8923}
8924
8925
8926// Create a plain JSObject which materializes the closure content for the
8927// context.
8928static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
8929 ASSERT(context->is_function_context());
8930
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008931 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008932 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8933 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008934
8935 // Allocate and initialize a JSObject with all the content of theis function
8936 // closure.
8937 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
8938
8939 // Check whether the arguments shadow object exists.
8940 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00008941 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
8942 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008943 if (arguments_shadow_index >= 0) {
8944 // In this case all the arguments are available in the arguments shadow
8945 // object.
8946 Handle<JSObject> arguments_shadow(
8947 JSObject::cast(context->get(arguments_shadow_index)));
8948 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008949 // We don't expect exception-throwing getters on the arguments shadow.
8950 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008951 SetProperty(closure_scope,
8952 scope_info.parameter_name(i),
lrn@chromium.org303ada72010-10-27 09:33:13 +00008953 Handle<Object>(element),
8954 NONE);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008955 }
8956 }
8957
8958 // Fill all context locals to the context extension.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008959 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
8960 context, closure_scope);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008961
8962 // Finally copy any properties from the function context extension. This will
8963 // be variables introduced by eval.
8964 if (context->has_extension()) {
8965 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008966 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008967 for (int i = 0; i < keys->length(); i++) {
8968 // Names of variables introduced by eval are strings.
8969 ASSERT(keys->get(i)->IsString());
8970 Handle<String> key(String::cast(keys->get(i)));
8971 SetProperty(closure_scope, key, GetProperty(ext, key), NONE);
8972 }
8973 }
8974
8975 return closure_scope;
8976}
8977
8978
8979// Iterate over the actual scopes visible from a stack frame. All scopes are
8980// backed by an actual context except the local scope, which is inserted
8981// "artifically" in the context chain.
8982class ScopeIterator {
8983 public:
8984 enum ScopeType {
8985 ScopeTypeGlobal = 0,
8986 ScopeTypeLocal,
8987 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00008988 ScopeTypeClosure,
8989 // Every catch block contains an implicit with block (its parameter is
8990 // a JSContextExtensionObject) that extends current scope with a variable
8991 // holding exception object. Such with blocks are treated as scopes of their
8992 // own type.
8993 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008994 };
8995
8996 explicit ScopeIterator(JavaScriptFrame* frame)
8997 : frame_(frame),
8998 function_(JSFunction::cast(frame->function())),
8999 context_(Context::cast(frame->context())),
9000 local_done_(false),
9001 at_local_(false) {
9002
9003 // Check whether the first scope is actually a local scope.
9004 if (context_->IsGlobalContext()) {
9005 // If there is a stack slot for .result then this local scope has been
9006 // created for evaluating top level code and it is not a real local scope.
9007 // Checking for the existence of .result seems fragile, but the scope info
9008 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009009 int index = function_->shared()->scope_info()->
9010 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009011 at_local_ = index < 0;
9012 } else if (context_->is_function_context()) {
9013 at_local_ = true;
9014 }
9015 }
9016
9017 // More scopes?
9018 bool Done() { return context_.is_null(); }
9019
9020 // Move to the next scope.
9021 void Next() {
9022 // If at a local scope mark the local scope as passed.
9023 if (at_local_) {
9024 at_local_ = false;
9025 local_done_ = true;
9026
9027 // If the current context is not associated with the local scope the
9028 // current context is the next real scope, so don't move to the next
9029 // context in this case.
9030 if (context_->closure() != *function_) {
9031 return;
9032 }
9033 }
9034
9035 // The global scope is always the last in the chain.
9036 if (context_->IsGlobalContext()) {
9037 context_ = Handle<Context>();
9038 return;
9039 }
9040
9041 // Move to the next context.
9042 if (context_->is_function_context()) {
9043 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9044 } else {
9045 context_ = Handle<Context>(context_->previous());
9046 }
9047
9048 // If passing the local scope indicate that the current scope is now the
9049 // local scope.
9050 if (!local_done_ &&
9051 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9052 at_local_ = true;
9053 }
9054 }
9055
9056 // Return the type of the current scope.
9057 int Type() {
9058 if (at_local_) {
9059 return ScopeTypeLocal;
9060 }
9061 if (context_->IsGlobalContext()) {
9062 ASSERT(context_->global()->IsGlobalObject());
9063 return ScopeTypeGlobal;
9064 }
9065 if (context_->is_function_context()) {
9066 return ScopeTypeClosure;
9067 }
9068 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009069 // Current scope is either an explicit with statement or a with statement
9070 // implicitely generated for a catch block.
9071 // If the extension object here is a JSContextExtensionObject then
9072 // current with statement is one frome a catch block otherwise it's a
9073 // regular with statement.
9074 if (context_->extension()->IsJSContextExtensionObject()) {
9075 return ScopeTypeCatch;
9076 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009077 return ScopeTypeWith;
9078 }
9079
9080 // Return the JavaScript object with the content of the current scope.
9081 Handle<JSObject> ScopeObject() {
9082 switch (Type()) {
9083 case ScopeIterator::ScopeTypeGlobal:
9084 return Handle<JSObject>(CurrentContext()->global());
9085 break;
9086 case ScopeIterator::ScopeTypeLocal:
9087 // Materialize the content of the local scope into a JSObject.
9088 return MaterializeLocalScope(frame_);
9089 break;
9090 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009091 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009092 // Return the with object.
9093 return Handle<JSObject>(CurrentContext()->extension());
9094 break;
9095 case ScopeIterator::ScopeTypeClosure:
9096 // Materialize the content of the closure scope into a JSObject.
9097 return MaterializeClosure(CurrentContext());
9098 break;
9099 }
9100 UNREACHABLE();
9101 return Handle<JSObject>();
9102 }
9103
9104 // Return the context for this scope. For the local context there might not
9105 // be an actual context.
9106 Handle<Context> CurrentContext() {
9107 if (at_local_ && context_->closure() != *function_) {
9108 return Handle<Context>();
9109 }
9110 return context_;
9111 }
9112
9113#ifdef DEBUG
9114 // Debug print of the content of the current scope.
9115 void DebugPrint() {
9116 switch (Type()) {
9117 case ScopeIterator::ScopeTypeGlobal:
9118 PrintF("Global:\n");
9119 CurrentContext()->Print();
9120 break;
9121
9122 case ScopeIterator::ScopeTypeLocal: {
9123 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009124 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009125 scope_info.Print();
9126 if (!CurrentContext().is_null()) {
9127 CurrentContext()->Print();
9128 if (CurrentContext()->has_extension()) {
9129 Handle<JSObject> extension =
9130 Handle<JSObject>(CurrentContext()->extension());
9131 if (extension->IsJSContextExtensionObject()) {
9132 extension->Print();
9133 }
9134 }
9135 }
9136 break;
9137 }
9138
9139 case ScopeIterator::ScopeTypeWith: {
9140 PrintF("With:\n");
9141 Handle<JSObject> extension =
9142 Handle<JSObject>(CurrentContext()->extension());
9143 extension->Print();
9144 break;
9145 }
9146
ager@chromium.orga1645e22009-09-09 19:27:10 +00009147 case ScopeIterator::ScopeTypeCatch: {
9148 PrintF("Catch:\n");
9149 Handle<JSObject> extension =
9150 Handle<JSObject>(CurrentContext()->extension());
9151 extension->Print();
9152 break;
9153 }
9154
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009155 case ScopeIterator::ScopeTypeClosure: {
9156 PrintF("Closure:\n");
9157 CurrentContext()->Print();
9158 if (CurrentContext()->has_extension()) {
9159 Handle<JSObject> extension =
9160 Handle<JSObject>(CurrentContext()->extension());
9161 if (extension->IsJSContextExtensionObject()) {
9162 extension->Print();
9163 }
9164 }
9165 break;
9166 }
9167
9168 default:
9169 UNREACHABLE();
9170 }
9171 PrintF("\n");
9172 }
9173#endif
9174
9175 private:
9176 JavaScriptFrame* frame_;
9177 Handle<JSFunction> function_;
9178 Handle<Context> context_;
9179 bool local_done_;
9180 bool at_local_;
9181
9182 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9183};
9184
9185
lrn@chromium.org303ada72010-10-27 09:33:13 +00009186static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009187 HandleScope scope;
9188 ASSERT(args.length() == 2);
9189
9190 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009191 Object* check;
9192 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9193 if (!maybe_check->ToObject(&check)) return maybe_check;
9194 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009195 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9196
9197 // Get the frame where the debugging is performed.
9198 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9199 JavaScriptFrameIterator it(id);
9200 JavaScriptFrame* frame = it.frame();
9201
9202 // Count the visible scopes.
9203 int n = 0;
9204 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9205 n++;
9206 }
9207
9208 return Smi::FromInt(n);
9209}
9210
9211
9212static const int kScopeDetailsTypeIndex = 0;
9213static const int kScopeDetailsObjectIndex = 1;
9214static const int kScopeDetailsSize = 2;
9215
9216// Return an array with scope details
9217// args[0]: number: break id
9218// args[1]: number: frame index
9219// args[2]: number: scope index
9220//
9221// The array returned contains the following information:
9222// 0: Scope type
9223// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009224static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009225 HandleScope scope;
9226 ASSERT(args.length() == 3);
9227
9228 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009229 Object* check;
9230 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9231 if (!maybe_check->ToObject(&check)) return maybe_check;
9232 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009233 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9234 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9235
9236 // Get the frame where the debugging is performed.
9237 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9238 JavaScriptFrameIterator frame_it(id);
9239 JavaScriptFrame* frame = frame_it.frame();
9240
9241 // Find the requested scope.
9242 int n = 0;
9243 ScopeIterator it(frame);
9244 for (; !it.Done() && n < index; it.Next()) {
9245 n++;
9246 }
9247 if (it.Done()) {
9248 return Heap::undefined_value();
9249 }
9250
9251 // Calculate the size of the result.
9252 int details_size = kScopeDetailsSize;
9253 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9254
9255 // Fill in scope details.
9256 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009257 Handle<JSObject> scope_object = it.ScopeObject();
9258 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009259
9260 return *Factory::NewJSArrayWithElements(details);
9261}
9262
9263
lrn@chromium.org303ada72010-10-27 09:33:13 +00009264static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009265 HandleScope scope;
9266 ASSERT(args.length() == 0);
9267
9268#ifdef DEBUG
9269 // Print the scopes for the top frame.
9270 StackFrameLocator locator;
9271 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9272 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9273 it.DebugPrint();
9274 }
9275#endif
9276 return Heap::undefined_value();
9277}
9278
9279
lrn@chromium.org303ada72010-10-27 09:33:13 +00009280static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009281 HandleScope scope;
9282 ASSERT(args.length() == 1);
9283
9284 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009285 Object* result;
9286 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9287 if (!maybe_result->ToObject(&result)) return maybe_result;
9288 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009289
9290 // Count all archived V8 threads.
9291 int n = 0;
9292 for (ThreadState* thread = ThreadState::FirstInUse();
9293 thread != NULL;
9294 thread = thread->Next()) {
9295 n++;
9296 }
9297
9298 // Total number of threads is current thread and archived threads.
9299 return Smi::FromInt(n + 1);
9300}
9301
9302
9303static const int kThreadDetailsCurrentThreadIndex = 0;
9304static const int kThreadDetailsThreadIdIndex = 1;
9305static const int kThreadDetailsSize = 2;
9306
9307// Return an array with thread details
9308// args[0]: number: break id
9309// args[1]: number: thread index
9310//
9311// The array returned contains the following information:
9312// 0: Is current thread?
9313// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00009314static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009315 HandleScope scope;
9316 ASSERT(args.length() == 2);
9317
9318 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009319 Object* check;
9320 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9321 if (!maybe_check->ToObject(&check)) return maybe_check;
9322 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009323 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9324
9325 // Allocate array for result.
9326 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9327
9328 // Thread index 0 is current thread.
9329 if (index == 0) {
9330 // Fill the details.
9331 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9332 details->set(kThreadDetailsThreadIdIndex,
9333 Smi::FromInt(ThreadManager::CurrentId()));
9334 } else {
9335 // Find the thread with the requested index.
9336 int n = 1;
9337 ThreadState* thread = ThreadState::FirstInUse();
9338 while (index != n && thread != NULL) {
9339 thread = thread->Next();
9340 n++;
9341 }
9342 if (thread == NULL) {
9343 return Heap::undefined_value();
9344 }
9345
9346 // Fill the details.
9347 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9348 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9349 }
9350
9351 // Convert to JS array and return.
9352 return *Factory::NewJSArrayWithElements(details);
9353}
9354
9355
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009356// Sets the disable break state
9357// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00009358static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009359 HandleScope scope;
9360 ASSERT(args.length() == 1);
9361 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9362 Debug::set_disable_break(disable_break);
9363 return Heap::undefined_value();
9364}
9365
9366
lrn@chromium.org303ada72010-10-27 09:33:13 +00009367static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009368 HandleScope scope;
9369 ASSERT(args.length() == 1);
9370
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009371 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9372 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009373 // Find the number of break points
9374 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9375 if (break_locations->IsUndefined()) return Heap::undefined_value();
9376 // Return array as JS array
9377 return *Factory::NewJSArrayWithElements(
9378 Handle<FixedArray>::cast(break_locations));
9379}
9380
9381
9382// Set a break point in a function
9383// args[0]: function
9384// args[1]: number: break source position (within the function source)
9385// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009386static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009387 HandleScope scope;
9388 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009389 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9390 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009391 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9392 RUNTIME_ASSERT(source_position >= 0);
9393 Handle<Object> break_point_object_arg = args.at<Object>(2);
9394
9395 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009396 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009397
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009398 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009399}
9400
9401
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009402Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9403 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009404 // Iterate the heap looking for SharedFunctionInfo generated from the
9405 // script. The inner most SharedFunctionInfo containing the source position
9406 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009407 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009408 // which is found is not compiled it is compiled and the heap is iterated
9409 // again as the compilation might create inner functions from the newly
9410 // compiled function and the actual requested break point might be in one of
9411 // these functions.
9412 bool done = false;
9413 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009414 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009415 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009416 while (!done) {
9417 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009418 for (HeapObject* obj = iterator.next();
9419 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009420 if (obj->IsSharedFunctionInfo()) {
9421 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9422 if (shared->script() == *script) {
9423 // If the SharedFunctionInfo found has the requested script data and
9424 // contains the source position it is a candidate.
9425 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009426 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009427 start_position = shared->start_position();
9428 }
9429 if (start_position <= position &&
9430 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009431 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009432 // candidate this is the new candidate.
9433 if (target.is_null()) {
9434 target_start_position = start_position;
9435 target = shared;
9436 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009437 if (target_start_position == start_position &&
9438 shared->end_position() == target->end_position()) {
9439 // If a top-level function contain only one function
9440 // declartion the source for the top-level and the function is
9441 // the same. In that case prefer the non top-level function.
9442 if (!shared->is_toplevel()) {
9443 target_start_position = start_position;
9444 target = shared;
9445 }
9446 } else if (target_start_position <= start_position &&
9447 shared->end_position() <= target->end_position()) {
9448 // This containment check includes equality as a function inside
9449 // a top-level function can share either start or end position
9450 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009451 target_start_position = start_position;
9452 target = shared;
9453 }
9454 }
9455 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009456 }
9457 }
9458 }
9459
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009460 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009461 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009462 }
9463
9464 // If the candidate found is compiled we are done. NOTE: when lazy
9465 // compilation of inner functions is introduced some additional checking
9466 // needs to be done here to compile inner functions.
9467 done = target->is_compiled();
9468 if (!done) {
9469 // If the candidate is not compiled compile it to reveal any inner
9470 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009471 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009472 }
9473 }
9474
9475 return *target;
9476}
9477
9478
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009479// Changes the state of a break point in a script and returns source position
9480// where break point was set. NOTE: Regarding performance see the NOTE for
9481// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009482// args[0]: script to set break point in
9483// args[1]: number: break source position (within the script source)
9484// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009485static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009486 HandleScope scope;
9487 ASSERT(args.length() == 3);
9488 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9489 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9490 RUNTIME_ASSERT(source_position >= 0);
9491 Handle<Object> break_point_object_arg = args.at<Object>(2);
9492
9493 // Get the script from the script wrapper.
9494 RUNTIME_ASSERT(wrapper->value()->IsScript());
9495 Handle<Script> script(Script::cast(wrapper->value()));
9496
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009497 Object* result = Runtime::FindSharedFunctionInfoInScript(
9498 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009499 if (!result->IsUndefined()) {
9500 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9501 // Find position within function. The script position might be before the
9502 // source position of the first function.
9503 int position;
9504 if (shared->start_position() > source_position) {
9505 position = 0;
9506 } else {
9507 position = source_position - shared->start_position();
9508 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009509 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9510 position += shared->start_position();
9511 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009512 }
9513 return Heap::undefined_value();
9514}
9515
9516
9517// Clear a break point
9518// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009519static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009520 HandleScope scope;
9521 ASSERT(args.length() == 1);
9522 Handle<Object> break_point_object_arg = args.at<Object>(0);
9523
9524 // Clear break point.
9525 Debug::ClearBreakPoint(break_point_object_arg);
9526
9527 return Heap::undefined_value();
9528}
9529
9530
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009531// Change the state of break on exceptions.
9532// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9533// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009534static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009535 HandleScope scope;
9536 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009537 RUNTIME_ASSERT(args[0]->IsNumber());
9538 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009539
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009540 // If the number doesn't match an enum value, the ChangeBreakOnException
9541 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009542 ExceptionBreakType type =
9543 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009544 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009545 Debug::ChangeBreakOnException(type, enable);
9546 return Heap::undefined_value();
9547}
9548
9549
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009550// Returns the state of break on exceptions
9551// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +00009552static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009553 HandleScope scope;
9554 ASSERT(args.length() == 1);
9555 RUNTIME_ASSERT(args[0]->IsNumber());
9556
9557 ExceptionBreakType type =
9558 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9559 bool result = Debug::IsBreakOnException(type);
9560 return Smi::FromInt(result);
9561}
9562
9563
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009564// Prepare for stepping
9565// args[0]: break id for checking execution state
9566// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009567// args[2]: number of times to perform the step, for step out it is the number
9568// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009569static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009570 HandleScope scope;
9571 ASSERT(args.length() == 3);
9572 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009573 Object* check;
9574 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9575 if (!maybe_check->ToObject(&check)) return maybe_check;
9576 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009577 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9578 return Top::Throw(Heap::illegal_argument_symbol());
9579 }
9580
9581 // Get the step action and check validity.
9582 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9583 if (step_action != StepIn &&
9584 step_action != StepNext &&
9585 step_action != StepOut &&
9586 step_action != StepInMin &&
9587 step_action != StepMin) {
9588 return Top::Throw(Heap::illegal_argument_symbol());
9589 }
9590
9591 // Get the number of steps.
9592 int step_count = NumberToInt32(args[2]);
9593 if (step_count < 1) {
9594 return Top::Throw(Heap::illegal_argument_symbol());
9595 }
9596
ager@chromium.orga1645e22009-09-09 19:27:10 +00009597 // Clear all current stepping setup.
9598 Debug::ClearStepping();
9599
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009600 // Prepare step.
9601 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9602 return Heap::undefined_value();
9603}
9604
9605
9606// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009607static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009608 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009609 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009610 Debug::ClearStepping();
9611 return Heap::undefined_value();
9612}
9613
9614
9615// Creates a copy of the with context chain. The copy of the context chain is
9616// is linked to the function context supplied.
9617static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9618 Handle<Context> function_context) {
9619 // At the bottom of the chain. Return the function context to link to.
9620 if (context_chain->is_function_context()) {
9621 return function_context;
9622 }
9623
9624 // Recursively copy the with contexts.
9625 Handle<Context> previous(context_chain->previous());
9626 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009627 Handle<Context> context = CopyWithContextChain(function_context, previous);
9628 return Factory::NewWithContext(context,
9629 extension,
9630 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009631}
9632
9633
9634// Helper function to find or create the arguments object for
9635// Runtime_DebugEvaluate.
9636static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9637 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009638 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009639 const ScopeInfo<>* sinfo,
9640 Handle<Context> function_context) {
9641 // Try to find the value of 'arguments' to pass as parameter. If it is not
9642 // found (that is the debugged function does not reference 'arguments' and
9643 // does not support eval) then create an 'arguments' object.
9644 int index;
9645 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009646 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009647 if (index != -1) {
9648 return Handle<Object>(frame->GetExpression(index));
9649 }
9650 }
9651
9652 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009653 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009654 if (index != -1) {
9655 return Handle<Object>(function_context->get(index));
9656 }
9657 }
9658
9659 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009660 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9661 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009662
9663 AssertNoAllocation no_gc;
9664 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009665 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009666 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009667 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009668 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009669 return arguments;
9670}
9671
9672
9673// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009674// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009675// extension part has all the parameters and locals of the function on the
9676// stack frame. A function which calls eval with the code to evaluate is then
9677// compiled in this context and called in this context. As this context
9678// replaces the context of the function on the stack frame a new (empty)
9679// function is created as well to be used as the closure for the context.
9680// This function and the context acts as replacements for the function on the
9681// stack frame presenting the same view of the values of parameters and
9682// local variables as if the piece of JavaScript was evaluated at the point
9683// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009684static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009685 HandleScope scope;
9686
9687 // Check the execution state and decode arguments frame and source to be
9688 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009689 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009690 Object* check_result;
9691 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9692 if (!maybe_check_result->ToObject(&check_result)) {
9693 return maybe_check_result;
9694 }
9695 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009696 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9697 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009698 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009699 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009700
9701 // Handle the processing of break.
9702 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009703
9704 // Get the frame where the debugging is performed.
9705 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9706 JavaScriptFrameIterator it(id);
9707 JavaScriptFrame* frame = it.frame();
9708 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009709 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009710 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009711
9712 // Traverse the saved contexts chain to find the active context for the
9713 // selected frame.
9714 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009715 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009716 save = save->prev();
9717 }
9718 ASSERT(save != NULL);
9719 SaveContext savex;
9720 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009721
9722 // Create the (empty) function replacing the function on the stack frame for
9723 // the purpose of evaluating in the context created below. It is important
9724 // that this function does not describe any parameters and local variables
9725 // in the context. If it does then this will cause problems with the lookup
9726 // in Context::Lookup, where context slots for parameters and local variables
9727 // are looked at before the extension object.
9728 Handle<JSFunction> go_between =
9729 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9730 go_between->set_context(function->context());
9731#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009732 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009733 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9734 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9735#endif
9736
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009737 // Materialize the content of the local scope into a JSObject.
9738 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009739
9740 // Allocate a new context for the debug evaluation and set the extension
9741 // object build.
9742 Handle<Context> context =
9743 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009744 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009745 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009746 Handle<Context> frame_context(Context::cast(frame->context()));
9747 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009748 context = CopyWithContextChain(frame_context, context);
9749
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009750 if (additional_context->IsJSObject()) {
9751 context = Factory::NewWithContext(context,
9752 Handle<JSObject>::cast(additional_context), false);
9753 }
9754
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009755 // Wrap the evaluation statement in a new function compiled in the newly
9756 // created context. The function has one parameter which has to be called
9757 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00009758 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009759 // function(arguments,__source__) {return eval(__source__);}
9760 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009761 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009762 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009763 Handle<String> function_source =
9764 Factory::NewStringFromAscii(Vector<const char>(source_str,
9765 source_str_length));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009766 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +00009767 Compiler::CompileEval(function_source,
9768 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009769 context->IsGlobalContext());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009770 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009771 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009772 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009773
9774 // Invoke the result of the compilation to get the evaluation function.
9775 bool has_pending_exception;
9776 Handle<Object> receiver(frame->receiver());
9777 Handle<Object> evaluation_function =
9778 Execution::Call(compiled_function, receiver, 0, NULL,
9779 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009780 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009781
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009782 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
9783 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009784
9785 // Invoke the evaluation function and return the result.
9786 const int argc = 2;
9787 Object** argv[argc] = { arguments.location(),
9788 Handle<Object>::cast(source).location() };
9789 Handle<Object> result =
9790 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
9791 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009792 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009793
9794 // Skip the global proxy as it has no properties and always delegates to the
9795 // real global object.
9796 if (result->IsJSGlobalProxy()) {
9797 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
9798 }
9799
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009800 return *result;
9801}
9802
9803
lrn@chromium.org303ada72010-10-27 09:33:13 +00009804static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009805 HandleScope scope;
9806
9807 // Check the execution state and decode arguments frame and source to be
9808 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009809 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009810 Object* check_result;
9811 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9812 if (!maybe_check_result->ToObject(&check_result)) {
9813 return maybe_check_result;
9814 }
9815 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009816 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009817 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009818 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009819
9820 // Handle the processing of break.
9821 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009822
9823 // Enter the top context from before the debugger was invoked.
9824 SaveContext save;
9825 SaveContext* top = &save;
9826 while (top != NULL && *top->context() == *Debug::debug_context()) {
9827 top = top->prev();
9828 }
9829 if (top != NULL) {
9830 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009831 }
9832
9833 // Get the global context now set to the top context from before the
9834 // debugger was invoked.
9835 Handle<Context> context = Top::global_context();
9836
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009837 bool is_global = true;
9838
9839 if (additional_context->IsJSObject()) {
9840 // Create a function context first, than put 'with' context on top of it.
9841 Handle<JSFunction> go_between = Factory::NewFunction(
9842 Factory::empty_string(), Factory::undefined_value());
9843 go_between->set_context(*context);
9844 context =
9845 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
9846 context->set_extension(JSObject::cast(*additional_context));
9847 is_global = false;
9848 }
9849
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009850 // Compile the source to be evaluated.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009851 Handle<SharedFunctionInfo> shared =
9852 Compiler::CompileEval(source,
9853 context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009854 is_global);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009855 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009856 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009857 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
9858 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009859
9860 // Invoke the result of the compilation to get the evaluation function.
9861 bool has_pending_exception;
9862 Handle<Object> receiver = Top::global();
9863 Handle<Object> result =
9864 Execution::Call(compiled_function, receiver, 0, NULL,
9865 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009866 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009867 return *result;
9868}
9869
9870
lrn@chromium.org303ada72010-10-27 09:33:13 +00009871static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009872 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009873 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009874
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009875 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009876 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009877
9878 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009879 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00009880 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
9881 // Get the script wrapper in a local handle before calling GetScriptWrapper,
9882 // because using
9883 // instances->set(i, *GetScriptWrapper(script))
9884 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
9885 // already have deferenced the instances handle.
9886 Handle<JSValue> wrapper = GetScriptWrapper(script);
9887 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009888 }
9889
9890 // Return result as a JS array.
9891 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
9892 Handle<JSArray>::cast(result)->SetContent(*instances);
9893 return *result;
9894}
9895
9896
9897// Helper function used by Runtime_DebugReferencedBy below.
9898static int DebugReferencedBy(JSObject* target,
9899 Object* instance_filter, int max_references,
9900 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009901 JSFunction* arguments_function) {
9902 NoHandleAllocation ha;
9903 AssertNoAllocation no_alloc;
9904
9905 // Iterate the heap.
9906 int count = 0;
9907 JSObject* last = NULL;
9908 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009909 HeapObject* heap_obj = NULL;
9910 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009911 (max_references == 0 || count < max_references)) {
9912 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009913 if (heap_obj->IsJSObject()) {
9914 // Skip context extension objects and argument arrays as these are
9915 // checked in the context of functions using them.
9916 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009917 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009918 obj->map()->constructor() == arguments_function) {
9919 continue;
9920 }
9921
9922 // Check if the JS object has a reference to the object looked for.
9923 if (obj->ReferencesObject(target)) {
9924 // Check instance filter if supplied. This is normally used to avoid
9925 // references from mirror objects (see Runtime_IsInPrototypeChain).
9926 if (!instance_filter->IsUndefined()) {
9927 Object* V = obj;
9928 while (true) {
9929 Object* prototype = V->GetPrototype();
9930 if (prototype->IsNull()) {
9931 break;
9932 }
9933 if (instance_filter == prototype) {
9934 obj = NULL; // Don't add this object.
9935 break;
9936 }
9937 V = prototype;
9938 }
9939 }
9940
9941 if (obj != NULL) {
9942 // Valid reference found add to instance array if supplied an update
9943 // count.
9944 if (instances != NULL && count < instances_size) {
9945 instances->set(count, obj);
9946 }
9947 last = obj;
9948 count++;
9949 }
9950 }
9951 }
9952 }
9953
9954 // Check for circular reference only. This can happen when the object is only
9955 // referenced from mirrors and has a circular reference in which case the
9956 // object is not really alive and would have been garbage collected if not
9957 // referenced from the mirror.
9958 if (count == 1 && last == target) {
9959 count = 0;
9960 }
9961
9962 // Return the number of referencing objects found.
9963 return count;
9964}
9965
9966
9967// Scan the heap for objects with direct references to an object
9968// args[0]: the object to find references to
9969// args[1]: constructor function for instances to exclude (Mirror)
9970// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +00009971static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009972 ASSERT(args.length() == 3);
9973
9974 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009975 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009976
9977 // Check parameters.
9978 CONVERT_CHECKED(JSObject, target, args[0]);
9979 Object* instance_filter = args[1];
9980 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
9981 instance_filter->IsJSObject());
9982 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
9983 RUNTIME_ASSERT(max_references >= 0);
9984
9985 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009986 JSObject* arguments_boilerplate =
9987 Top::context()->global_context()->arguments_boilerplate();
9988 JSFunction* arguments_function =
9989 JSFunction::cast(arguments_boilerplate->map()->constructor());
9990
9991 // Get the number of referencing objects.
9992 int count;
9993 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009994 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009995
9996 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009997 Object* object;
9998 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
9999 if (!maybe_object->ToObject(&object)) return maybe_object;
10000 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010001 FixedArray* instances = FixedArray::cast(object);
10002
10003 // Fill the referencing objects.
10004 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010005 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010006
10007 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010008 Object* result;
10009 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10010 Top::context()->global_context()->array_function());
10011 if (!maybe_result->ToObject(&result)) return maybe_result;
10012 }
10013 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010014 return result;
10015}
10016
10017
10018// Helper function used by Runtime_DebugConstructedBy below.
10019static int DebugConstructedBy(JSFunction* constructor, int max_references,
10020 FixedArray* instances, int instances_size) {
10021 AssertNoAllocation no_alloc;
10022
10023 // Iterate the heap.
10024 int count = 0;
10025 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010026 HeapObject* heap_obj = NULL;
10027 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010028 (max_references == 0 || count < max_references)) {
10029 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010030 if (heap_obj->IsJSObject()) {
10031 JSObject* obj = JSObject::cast(heap_obj);
10032 if (obj->map()->constructor() == constructor) {
10033 // Valid reference found add to instance array if supplied an update
10034 // count.
10035 if (instances != NULL && count < instances_size) {
10036 instances->set(count, obj);
10037 }
10038 count++;
10039 }
10040 }
10041 }
10042
10043 // Return the number of referencing objects found.
10044 return count;
10045}
10046
10047
10048// Scan the heap for objects constructed by a specific function.
10049// args[0]: the constructor to find instances of
10050// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010051static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010052 ASSERT(args.length() == 2);
10053
10054 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010055 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010056
10057 // Check parameters.
10058 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10059 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10060 RUNTIME_ASSERT(max_references >= 0);
10061
10062 // Get the number of referencing objects.
10063 int count;
10064 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10065
10066 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010067 Object* object;
10068 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10069 if (!maybe_object->ToObject(&object)) return maybe_object;
10070 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010071 FixedArray* instances = FixedArray::cast(object);
10072
10073 // Fill the referencing objects.
10074 count = DebugConstructedBy(constructor, max_references, instances, count);
10075
10076 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010077 Object* result;
10078 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10079 Top::context()->global_context()->array_function());
10080 if (!maybe_result->ToObject(&result)) return maybe_result;
10081 }
10082 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010083 return result;
10084}
10085
10086
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010087// Find the effective prototype object as returned by __proto__.
10088// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010089static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010090 ASSERT(args.length() == 1);
10091
10092 CONVERT_CHECKED(JSObject, obj, args[0]);
10093
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010094 // Use the __proto__ accessor.
10095 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010096}
10097
10098
lrn@chromium.org303ada72010-10-27 09:33:13 +000010099static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010100 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010101 CPU::DebugBreak();
10102 return Heap::undefined_value();
10103}
10104
10105
lrn@chromium.org303ada72010-10-27 09:33:13 +000010106static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010107#ifdef DEBUG
10108 HandleScope scope;
10109 ASSERT(args.length() == 1);
10110 // Get the function and make sure it is compiled.
10111 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010112 Handle<SharedFunctionInfo> shared(func->shared());
10113 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010114 return Failure::Exception();
10115 }
10116 func->code()->PrintLn();
10117#endif // DEBUG
10118 return Heap::undefined_value();
10119}
ager@chromium.org9085a012009-05-11 19:22:57 +000010120
10121
lrn@chromium.org303ada72010-10-27 09:33:13 +000010122static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010123#ifdef DEBUG
10124 HandleScope scope;
10125 ASSERT(args.length() == 1);
10126 // Get the function and make sure it is compiled.
10127 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010128 Handle<SharedFunctionInfo> shared(func->shared());
10129 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010130 return Failure::Exception();
10131 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010132 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010133#endif // DEBUG
10134 return Heap::undefined_value();
10135}
10136
10137
lrn@chromium.org303ada72010-10-27 09:33:13 +000010138static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010139 NoHandleAllocation ha;
10140 ASSERT(args.length() == 1);
10141
10142 CONVERT_CHECKED(JSFunction, f, args[0]);
10143 return f->shared()->inferred_name();
10144}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010145
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010146
10147static int FindSharedFunctionInfosForScript(Script* script,
10148 FixedArray* buffer) {
10149 AssertNoAllocation no_allocations;
10150
10151 int counter = 0;
10152 int buffer_size = buffer->length();
10153 HeapIterator iterator;
10154 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10155 ASSERT(obj != NULL);
10156 if (!obj->IsSharedFunctionInfo()) {
10157 continue;
10158 }
10159 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10160 if (shared->script() != script) {
10161 continue;
10162 }
10163 if (counter < buffer_size) {
10164 buffer->set(counter, shared);
10165 }
10166 counter++;
10167 }
10168 return counter;
10169}
10170
10171// For a script finds all SharedFunctionInfo's in the heap that points
10172// to this script. Returns JSArray of SharedFunctionInfo wrapped
10173// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010174static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010175 Arguments args) {
10176 ASSERT(args.length() == 1);
10177 HandleScope scope;
10178 CONVERT_CHECKED(JSValue, script_value, args[0]);
10179
10180 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10181
10182 const int kBufferSize = 32;
10183
10184 Handle<FixedArray> array;
10185 array = Factory::NewFixedArray(kBufferSize);
10186 int number = FindSharedFunctionInfosForScript(*script, *array);
10187 if (number > kBufferSize) {
10188 array = Factory::NewFixedArray(number);
10189 FindSharedFunctionInfosForScript(*script, *array);
10190 }
10191
10192 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10193 result->set_length(Smi::FromInt(number));
10194
10195 LiveEdit::WrapSharedFunctionInfos(result);
10196
10197 return *result;
10198}
10199
10200// For a script calculates compilation information about all its functions.
10201// The script source is explicitly specified by the second argument.
10202// The source of the actual script is not used, however it is important that
10203// all generated code keeps references to this particular instance of script.
10204// Returns a JSArray of compilation infos. The array is ordered so that
10205// each function with all its descendant is always stored in a continues range
10206// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010207static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010208 ASSERT(args.length() == 2);
10209 HandleScope scope;
10210 CONVERT_CHECKED(JSValue, script, args[0]);
10211 CONVERT_ARG_CHECKED(String, source, 1);
10212 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10213
10214 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10215
10216 if (Top::has_pending_exception()) {
10217 return Failure::Exception();
10218 }
10219
10220 return result;
10221}
10222
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010223// Changes the source of the script to a new_source.
10224// If old_script_name is provided (i.e. is a String), also creates a copy of
10225// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010226static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010227 ASSERT(args.length() == 3);
10228 HandleScope scope;
10229 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10230 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010231 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010232
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010233 CONVERT_CHECKED(Script, original_script_pointer,
10234 original_script_value->value());
10235 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010236
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010237 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10238 new_source,
10239 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010240
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010241 if (old_script->IsScript()) {
10242 Handle<Script> script_handle(Script::cast(old_script));
10243 return *(GetScriptWrapper(script_handle));
10244 } else {
10245 return Heap::null_value();
10246 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010247}
10248
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010249
10250static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10251 ASSERT(args.length() == 1);
10252 HandleScope scope;
10253 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10254 return LiveEdit::FunctionSourceUpdated(shared_info);
10255}
10256
10257
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010258// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010259static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010260 ASSERT(args.length() == 2);
10261 HandleScope scope;
10262 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10263 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10264
ager@chromium.orgac091b72010-05-05 07:34:42 +000010265 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010266}
10267
10268// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010269static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010270 ASSERT(args.length() == 2);
10271 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010272 Handle<Object> function_object(args[0]);
10273 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010274
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010275 if (function_object->IsJSValue()) {
10276 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10277 if (script_object->IsJSValue()) {
10278 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10279 script_object = Handle<Object>(script);
10280 }
10281
10282 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10283 } else {
10284 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10285 // and we check it in this function.
10286 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010287
10288 return Heap::undefined_value();
10289}
10290
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010291
10292// In a code of a parent function replaces original function as embedded object
10293// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010294static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010295 ASSERT(args.length() == 3);
10296 HandleScope scope;
10297
10298 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10299 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10300 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10301
10302 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10303 subst_wrapper);
10304
10305 return Heap::undefined_value();
10306}
10307
10308
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010309// Updates positions of a shared function info (first parameter) according
10310// to script source change. Text change is described in second parameter as
10311// array of groups of 3 numbers:
10312// (change_begin, change_end, change_end_new_position).
10313// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010314static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010315 ASSERT(args.length() == 2);
10316 HandleScope scope;
10317 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10318 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10319
ager@chromium.orgac091b72010-05-05 07:34:42 +000010320 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010321}
10322
10323
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010324// For array of SharedFunctionInfo's (each wrapped in JSValue)
10325// checks that none of them have activations on stacks (of any thread).
10326// Returns array of the same length with corresponding results of
10327// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010328static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010329 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010330 HandleScope scope;
10331 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000010332 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010333
ager@chromium.org357bf652010-04-12 11:30:10 +000010334 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010335}
10336
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010337// Compares 2 strings line-by-line and returns diff in form of JSArray of
fschneider@chromium.org013f3e12010-04-26 13:27:52 +000010338// triplets (pos1, pos1_end, pos2_end) describing list of diff chunks.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010339static MaybeObject* Runtime_LiveEditCompareStringsLinewise(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010340 ASSERT(args.length() == 2);
10341 HandleScope scope;
10342 CONVERT_ARG_CHECKED(String, s1, 0);
10343 CONVERT_ARG_CHECKED(String, s2, 1);
10344
10345 return *LiveEdit::CompareStringsLinewise(s1, s2);
10346}
10347
10348
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010349
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010350// A testing entry. Returns statement position which is the closest to
10351// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010352static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010353 ASSERT(args.length() == 2);
10354 HandleScope scope;
10355 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10356 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10357
10358 Handle<Code> code(function->code());
10359
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010360 if (code->kind() != Code::FUNCTION &&
10361 code->kind() != Code::OPTIMIZED_FUNCTION) {
10362 return Heap::undefined_value();
10363 }
10364
10365 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010366 int closest_pc = 0;
10367 int distance = kMaxInt;
10368 while (!it.done()) {
10369 int statement_position = static_cast<int>(it.rinfo()->data());
10370 // Check if this break point is closer that what was previously found.
10371 if (source_position <= statement_position &&
10372 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000010373 closest_pc =
10374 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010375 distance = statement_position - source_position;
10376 // Check whether we can't get any closer.
10377 if (distance == 0) break;
10378 }
10379 it.next();
10380 }
10381
10382 return Smi::FromInt(closest_pc);
10383}
10384
10385
ager@chromium.org357bf652010-04-12 11:30:10 +000010386// Calls specified function with or without entering the debugger.
10387// This is used in unit tests to run code as if debugger is entered or simply
10388// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010389static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010390 ASSERT(args.length() == 2);
10391 HandleScope scope;
10392 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10393 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10394
10395 Handle<Object> result;
10396 bool pending_exception;
10397 {
10398 if (without_debugger) {
10399 result = Execution::Call(function, Top::global(), 0, NULL,
10400 &pending_exception);
10401 } else {
10402 EnterDebugger enter_debugger;
10403 result = Execution::Call(function, Top::global(), 0, NULL,
10404 &pending_exception);
10405 }
10406 }
10407 if (!pending_exception) {
10408 return *result;
10409 } else {
10410 return Failure::Exception();
10411 }
10412}
10413
10414
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010415// Sets a v8 flag.
10416static MaybeObject* Runtime_SetFlags(Arguments args) {
10417 CONVERT_CHECKED(String, arg, args[0]);
10418 SmartPointer<char> flags =
10419 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
10420 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
10421 return Heap::undefined_value();
10422}
10423
10424
10425// Performs a GC.
10426// Presently, it only does a full GC.
10427static MaybeObject* Runtime_CollectGarbage(Arguments args) {
10428 Heap::CollectAllGarbage(true);
10429 return Heap::undefined_value();
10430}
10431
10432
10433// Gets the current heap usage.
10434static MaybeObject* Runtime_GetHeapUsage(Arguments args) {
10435 int usage = static_cast<int>(Heap::SizeOfObjects());
10436 if (!Smi::IsValid(usage)) {
10437 return *Factory::NewNumberFromInt(usage);
10438 }
10439 return Smi::FromInt(usage);
10440}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010441#endif // ENABLE_DEBUGGER_SUPPORT
10442
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010443
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010444#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org303ada72010-10-27 09:33:13 +000010445static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010446 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010447 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010448
10449 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010450 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10451 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010452 return Heap::undefined_value();
10453}
10454
10455
lrn@chromium.org303ada72010-10-27 09:33:13 +000010456static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010457 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010458 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010459
10460 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010461 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10462 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010463 return Heap::undefined_value();
10464}
10465
10466#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010467
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010468// Finds the script object from the script data. NOTE: This operation uses
10469// heap traversal to find the function generated for the source position
10470// for the requested break point. For lazily compiled functions several heap
10471// traversals might be required rendering this operation as a rather slow
10472// operation. However for setting break points which is normally done through
10473// some kind of user interaction the performance is not crucial.
10474static Handle<Object> Runtime_GetScriptFromScriptName(
10475 Handle<String> script_name) {
10476 // Scan the heap for Script objects to find the script with the requested
10477 // script data.
10478 Handle<Script> script;
10479 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010480 HeapObject* obj = NULL;
10481 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010482 // If a script is found check if it has the script data requested.
10483 if (obj->IsScript()) {
10484 if (Script::cast(obj)->name()->IsString()) {
10485 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
10486 script = Handle<Script>(Script::cast(obj));
10487 }
10488 }
10489 }
10490 }
10491
10492 // If no script with the requested script data is found return undefined.
10493 if (script.is_null()) return Factory::undefined_value();
10494
10495 // Return the script found.
10496 return GetScriptWrapper(script);
10497}
10498
10499
10500// Get the script object from script data. NOTE: Regarding performance
10501// see the NOTE for GetScriptFromScriptData.
10502// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000010503static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010504 HandleScope scope;
10505
10506 ASSERT(args.length() == 1);
10507
10508 CONVERT_CHECKED(String, script_name, args[0]);
10509
10510 // Find the requested script.
10511 Handle<Object> result =
10512 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10513 return *result;
10514}
10515
10516
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010517// Determines whether the given stack frame should be displayed in
10518// a stack trace. The caller is the error constructor that asked
10519// for the stack trace to be collected. The first time a construct
10520// call to this function is encountered it is skipped. The seen_caller
10521// in/out parameter is used to remember if the caller has been seen
10522// yet.
10523static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10524 bool* seen_caller) {
10525 // Only display JS frames.
10526 if (!raw_frame->is_java_script())
10527 return false;
10528 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10529 Object* raw_fun = frame->function();
10530 // Not sure when this can happen but skip it just in case.
10531 if (!raw_fun->IsJSFunction())
10532 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010533 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010534 *seen_caller = true;
10535 return false;
10536 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010537 // Skip all frames until we've seen the caller. Also, skip the most
10538 // obvious builtin calls. Some builtin calls (such as Number.ADD
10539 // which is invoked using 'call') are very difficult to recognize
10540 // so we're leaving them in for now.
10541 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010542}
10543
10544
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010545// Collect the raw data for a stack trace. Returns an array of 4
10546// element segments each containing a receiver, function, code and
10547// native code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010548static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010549 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010550 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010551 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10552
10553 HandleScope scope;
10554
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000010555 limit = Max(limit, 0); // Ensure that limit is not negative.
10556 int initial_size = Min(limit, 10);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010557 Handle<JSArray> result = Factory::NewJSArray(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010558
10559 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010560 // If the caller parameter is a function we skip frames until we're
10561 // under it before starting to collect.
10562 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010563 int cursor = 0;
10564 int frames_seen = 0;
10565 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010566 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010567 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010568 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010569 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010570 List<FrameSummary> frames(3); // Max 2 levels of inlining.
10571 frame->Summarize(&frames);
10572 for (int i = frames.length() - 1; i >= 0; i--) {
10573 Handle<Object> recv = frames[i].receiver();
10574 Handle<JSFunction> fun = frames[i].function();
10575 Handle<Code> code = frames[i].code();
10576 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
10577 FixedArray* elements = FixedArray::cast(result->elements());
10578 if (cursor + 3 < elements->length()) {
10579 elements->set(cursor++, *recv);
10580 elements->set(cursor++, *fun);
10581 elements->set(cursor++, *code);
10582 elements->set(cursor++, *offset);
10583 } else {
10584 SetElement(result, cursor++, recv);
10585 SetElement(result, cursor++, fun);
10586 SetElement(result, cursor++, code);
10587 SetElement(result, cursor++, offset);
10588 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010589 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010590 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010591 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010592 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010593
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010594 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010595 return *result;
10596}
10597
10598
ager@chromium.org3811b432009-10-28 14:53:37 +000010599// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010600static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010601 ASSERT_EQ(args.length(), 0);
10602
10603 NoHandleAllocation ha;
10604
10605 const char* version_string = v8::V8::GetVersion();
10606
10607 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
10608}
10609
10610
lrn@chromium.org303ada72010-10-27 09:33:13 +000010611static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010612 ASSERT(args.length() == 2);
10613 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10614 Smi::cast(args[1])->value());
10615 Top::PrintStack();
10616 OS::Abort();
10617 UNREACHABLE();
10618 return NULL;
10619}
10620
10621
lrn@chromium.org303ada72010-10-27 09:33:13 +000010622MUST_USE_RESULT static MaybeObject* CacheMiss(FixedArray* cache_obj,
10623 int index,
10624 Object* key_obj) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010625 ASSERT(index % 2 == 0); // index of the key
10626 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
10627 ASSERT(index < cache_obj->length());
10628
10629 HandleScope scope;
10630
10631 Handle<FixedArray> cache(cache_obj);
10632 Handle<Object> key(key_obj);
10633 Handle<JSFunction> factory(JSFunction::cast(
10634 cache->get(JSFunctionResultCache::kFactoryIndex)));
10635 // TODO(antonm): consider passing a receiver when constructing a cache.
10636 Handle<Object> receiver(Top::global_context()->global());
10637
10638 Handle<Object> value;
10639 {
10640 // This handle is nor shared, nor used later, so it's safe.
10641 Object** argv[] = { key.location() };
10642 bool pending_exception = false;
10643 value = Execution::Call(factory,
10644 receiver,
10645 1,
10646 argv,
10647 &pending_exception);
10648 if (pending_exception) return Failure::Exception();
10649 }
10650
10651 cache->set(index, *key);
10652 cache->set(index + 1, *value);
10653 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(index));
10654
10655 return *value;
10656}
10657
10658
lrn@chromium.org303ada72010-10-27 09:33:13 +000010659static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010660 // This is only called from codegen, so checks might be more lax.
10661 CONVERT_CHECKED(FixedArray, cache, args[0]);
10662 Object* key = args[1];
10663
10664 const int finger_index =
10665 Smi::cast(cache->get(JSFunctionResultCache::kFingerIndex))->value();
10666
10667 Object* o = cache->get(finger_index);
10668 if (o == key) {
10669 // The fastest case: hit the same place again.
10670 return cache->get(finger_index + 1);
10671 }
10672
10673 for (int i = finger_index - 2;
10674 i >= JSFunctionResultCache::kEntriesIndex;
10675 i -= 2) {
10676 o = cache->get(i);
10677 if (o == key) {
10678 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10679 return cache->get(i + 1);
10680 }
10681 }
10682
10683 const int size =
10684 Smi::cast(cache->get(JSFunctionResultCache::kCacheSizeIndex))->value();
10685 ASSERT(size <= cache->length());
10686
10687 for (int i = size - 2; i > finger_index; i -= 2) {
10688 o = cache->get(i);
10689 if (o == key) {
10690 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10691 return cache->get(i + 1);
10692 }
10693 }
10694
10695 // Cache miss. If we have spare room, put new data into it, otherwise
10696 // evict post finger entry which must be least recently used.
10697 if (size < cache->length()) {
10698 cache->set(JSFunctionResultCache::kCacheSizeIndex, Smi::FromInt(size + 2));
10699 return CacheMiss(cache, size, key);
10700 } else {
antonm@chromium.org397e23c2010-04-21 12:00:05 +000010701 int target_index = finger_index + JSFunctionResultCache::kEntrySize;
10702 if (target_index == cache->length()) {
10703 target_index = JSFunctionResultCache::kEntriesIndex;
10704 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010705 return CacheMiss(cache, target_index, key);
10706 }
10707}
10708
kasper.lund44510672008-07-25 07:37:58 +000010709#ifdef DEBUG
10710// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10711// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010712static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010713 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010714 HandleScope scope;
10715 Handle<JSArray> result = Factory::NewJSArray(0);
10716 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010717 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010718#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010719 { \
10720 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010721 Handle<String> name; \
10722 /* Inline runtime functions have an underscore in front of the name. */ \
10723 if (inline_runtime_functions) { \
10724 name = Factory::NewStringFromAscii( \
10725 Vector<const char>("_" #Name, StrLength("_" #Name))); \
10726 } else { \
10727 name = Factory::NewStringFromAscii( \
10728 Vector<const char>(#Name, StrLength(#Name))); \
10729 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010730 Handle<JSArray> pair = Factory::NewJSArray(0); \
10731 SetElement(pair, 0, name); \
10732 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
10733 SetElement(result, index++, pair); \
10734 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010735 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010736 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010737 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010738 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010739 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010740#undef ADD_ENTRY
10741 return *result;
10742}
kasper.lund44510672008-07-25 07:37:58 +000010743#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010744
10745
lrn@chromium.org303ada72010-10-27 09:33:13 +000010746static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010747 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010748 CONVERT_CHECKED(String, format, args[0]);
10749 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010750 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010751 Logger::LogRuntime(chars, elms);
10752 return Heap::undefined_value();
10753}
10754
10755
lrn@chromium.org303ada72010-10-27 09:33:13 +000010756static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010757 UNREACHABLE(); // implemented as macro in the parser
10758 return NULL;
10759}
10760
10761
10762// ----------------------------------------------------------------------------
10763// Implementation of Runtime
10764
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010765#define F(name, number_of_args, result_size) \
10766 { Runtime::k##name, Runtime::RUNTIME, #name, \
10767 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010768
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010769
10770#define I(name, number_of_args, result_size) \
10771 { Runtime::kInline##name, Runtime::INLINE, \
10772 "_" #name, NULL, number_of_args, result_size },
10773
10774Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010775 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010776 INLINE_FUNCTION_LIST(I)
10777 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010778};
10779
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010780
lrn@chromium.org303ada72010-10-27 09:33:13 +000010781MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010782 ASSERT(dictionary != NULL);
10783 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
10784 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010785 Object* name_symbol;
10786 { MaybeObject* maybe_name_symbol =
10787 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
10788 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
10789 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010790 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010791 { MaybeObject* maybe_dictionary = string_dictionary->Add(
10792 String::cast(name_symbol),
10793 Smi::FromInt(i),
10794 PropertyDetails(NONE, NORMAL));
10795 if (!maybe_dictionary->ToObject(&dictionary)) {
10796 // Non-recoverable failure. Calling code must restart heap
10797 // initialization.
10798 return maybe_dictionary;
10799 }
10800 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010801 }
10802 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010803}
10804
10805
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010806Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
10807 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
10808 if (entry != kNotFound) {
10809 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
10810 int function_index = Smi::cast(smi_index)->value();
10811 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010812 }
10813 return NULL;
10814}
10815
10816
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010817Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
10818 return &(kIntrinsicFunctions[static_cast<int>(id)]);
10819}
10820
10821
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010822void Runtime::PerformGC(Object* result) {
10823 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010824 if (failure->IsRetryAfterGC()) {
10825 // Try to do a garbage collection; ignore it if it fails. The C
10826 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000010827 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010828 } else {
10829 // Handle last resort GC and make sure to allow future allocations
10830 // to grow the heap without causing GCs (if possible).
10831 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010832 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010833 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010834}
10835
10836
10837} } // namespace v8::internal