blob: 4994378cd3a770e55a199a4582a2eeb35e81b470 [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.org83aa5492011-02-07 12:42:56 +0000647static bool CheckAccessException(LookupResult* result,
648 v8::AccessType access_type) {
649 if (result->type() == CALLBACKS) {
650 Object* callback = result->GetCallbackObject();
651 if (callback->IsAccessorInfo()) {
652 AccessorInfo* info = AccessorInfo::cast(callback);
653 bool can_access =
654 (access_type == v8::ACCESS_HAS &&
655 (info->all_can_read() || info->all_can_write())) ||
656 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
657 (access_type == v8::ACCESS_SET && info->all_can_write());
658 return can_access;
659 }
660 }
661
662 return false;
663}
664
665
666static bool CheckAccess(JSObject* obj,
667 String* name,
668 LookupResult* result,
669 v8::AccessType access_type) {
670 ASSERT(result->IsProperty());
671
672 JSObject* holder = result->holder();
673 JSObject* current = obj;
674 while (true) {
675 if (current->IsAccessCheckNeeded() &&
676 !Top::MayNamedAccess(current, name, access_type)) {
677 // Access check callback denied the access, but some properties
678 // can have a special permissions which override callbacks descision
679 // (currently see v8::AccessControl).
680 break;
681 }
682
683 if (current == holder) {
684 return true;
685 }
686
687 current = JSObject::cast(current->GetPrototype());
688 }
689
690 // API callbacks can have per callback access exceptions.
691 switch (result->type()) {
692 case CALLBACKS: {
693 if (CheckAccessException(result, access_type)) {
694 return true;
695 }
696 break;
697 }
698 case INTERCEPTOR: {
699 // If the object has an interceptor, try real named properties.
700 // Overwrite the result to fetch the correct property later.
701 holder->LookupRealNamedProperty(name, result);
702 if (result->IsProperty()) {
703 if (CheckAccessException(result, access_type)) {
704 return true;
705 }
706 }
707 break;
708 }
709 default:
710 break;
711 }
712
713 Top::ReportFailedAccessCheck(current, access_type);
714 return false;
715}
716
717
718// TODO(1095): we should traverse hidden prototype hierachy as well.
719static bool CheckElementAccess(JSObject* obj,
720 uint32_t index,
721 v8::AccessType access_type) {
722 if (obj->IsAccessCheckNeeded() &&
723 !Top::MayIndexedAccess(obj, index, access_type)) {
724 return false;
725 }
726
727 return true;
728}
729
730
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000731// Enumerator used as indices into the array returned from GetOwnProperty
732enum PropertyDescriptorIndices {
733 IS_ACCESSOR_INDEX,
734 VALUE_INDEX,
735 GETTER_INDEX,
736 SETTER_INDEX,
737 WRITABLE_INDEX,
738 ENUMERABLE_INDEX,
739 CONFIGURABLE_INDEX,
740 DESCRIPTOR_SIZE
741};
742
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000743// Returns an array with the property description:
744// if args[1] is not a property on args[0]
745// returns undefined
746// if args[1] is a data property on args[0]
747// [false, value, Writeable, Enumerable, Configurable]
748// if args[1] is an accessor on args[0]
749// [true, GetFunction, SetFunction, Enumerable, Configurable]
lrn@chromium.org303ada72010-10-27 09:33:13 +0000750static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000751 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000752 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000753 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000754 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
755 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000756 CONVERT_ARG_CHECKED(JSObject, obj, 0);
757 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000758
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000759 // This could be an element.
760 uint32_t index;
761 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000762 switch (obj->HasLocalElement(index)) {
763 case JSObject::UNDEFINED_ELEMENT:
764 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000765
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000766 case JSObject::STRING_CHARACTER_ELEMENT: {
767 // Special handling of string objects according to ECMAScript 5
768 // 15.5.5.2. Note that this might be a string object with elements
769 // other than the actual string value. This is covered by the
770 // subsequent cases.
771 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
772 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000773 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000774
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000775 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
776 elms->set(VALUE_INDEX, *substr);
777 elms->set(WRITABLE_INDEX, Heap::false_value());
778 elms->set(ENUMERABLE_INDEX, Heap::false_value());
779 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
780 return *desc;
781 }
782
783 case JSObject::INTERCEPTED_ELEMENT:
784 case JSObject::FAST_ELEMENT: {
785 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000786 elms->set(VALUE_INDEX, *GetElement(obj, index));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000787 elms->set(WRITABLE_INDEX, Heap::true_value());
788 elms->set(ENUMERABLE_INDEX, Heap::true_value());
789 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
790 return *desc;
791 }
792
793 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000794 Handle<JSObject> holder = obj;
795 if (obj->IsJSGlobalProxy()) {
796 Object* proto = obj->GetPrototype();
797 if (proto->IsNull()) return Heap::undefined_value();
798 ASSERT(proto->IsJSGlobalObject());
799 holder = Handle<JSObject>(JSObject::cast(proto));
800 }
801 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000802 int entry = dictionary->FindEntry(index);
803 ASSERT(entry != NumberDictionary::kNotFound);
804 PropertyDetails details = dictionary->DetailsAt(entry);
805 switch (details.type()) {
806 case CALLBACKS: {
807 // This is an accessor property with getter and/or setter.
808 FixedArray* callbacks =
809 FixedArray::cast(dictionary->ValueAt(entry));
810 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000811 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
812 elms->set(GETTER_INDEX, callbacks->get(0));
813 }
814 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
815 elms->set(SETTER_INDEX, callbacks->get(1));
816 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000817 break;
818 }
819 case NORMAL:
820 // This is a data property.
821 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000822 elms->set(VALUE_INDEX, *GetElement(obj, index));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000823 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
824 break;
825 default:
826 UNREACHABLE();
827 break;
828 }
829 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
830 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
831 return *desc;
832 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000833 }
834 }
835
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000836 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000837 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000838
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000839 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000840 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000841 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000842
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000843 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
844 return Heap::false_value();
845 }
846
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000847 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
848 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000849
850 bool is_js_accessor = (result.type() == CALLBACKS) &&
851 (result.GetCallbackObject()->IsFixedArray());
852
853 if (is_js_accessor) {
854 // __defineGetter__/__defineSetter__ callback.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000855 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000856
857 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
858 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
859 elms->set(GETTER_INDEX, structure->get(0));
860 }
861 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
862 elms->set(SETTER_INDEX, structure->get(1));
863 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000864 } else {
865 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
866 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
867
868 PropertyAttributes attrs;
869 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000870 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000871 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
872 if (!maybe_value->ToObject(&value)) return maybe_value;
873 }
874 elms->set(VALUE_INDEX, value);
875 }
876
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000877 return *desc;
878}
879
880
lrn@chromium.org303ada72010-10-27 09:33:13 +0000881static MaybeObject* Runtime_PreventExtensions(Arguments args) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000882 ASSERT(args.length() == 1);
883 CONVERT_CHECKED(JSObject, obj, args[0]);
884 return obj->PreventExtensions();
885}
886
lrn@chromium.org303ada72010-10-27 09:33:13 +0000887static MaybeObject* Runtime_IsExtensible(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000888 ASSERT(args.length() == 1);
889 CONVERT_CHECKED(JSObject, obj, args[0]);
890 return obj->map()->is_extensible() ? Heap::true_value()
891 : Heap::false_value();
892}
893
894
lrn@chromium.org303ada72010-10-27 09:33:13 +0000895static MaybeObject* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000896 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000897 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000898 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
899 CONVERT_ARG_CHECKED(String, pattern, 1);
900 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000901 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
902 if (result.is_null()) return Failure::Exception();
903 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000904}
905
906
lrn@chromium.org303ada72010-10-27 09:33:13 +0000907static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000908 HandleScope scope;
909 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000910 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000911 return *Factory::CreateApiFunction(data);
912}
913
914
lrn@chromium.org303ada72010-10-27 09:33:13 +0000915static MaybeObject* Runtime_IsTemplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000916 ASSERT(args.length() == 1);
917 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000918 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000919 return Heap::ToBoolean(result);
920}
921
922
lrn@chromium.org303ada72010-10-27 09:33:13 +0000923static MaybeObject* Runtime_GetTemplateField(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000924 ASSERT(args.length() == 2);
925 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000927 int index = field->value();
928 int offset = index * kPointerSize + HeapObject::kHeaderSize;
929 InstanceType type = templ->map()->instance_type();
930 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
931 type == OBJECT_TEMPLATE_INFO_TYPE);
932 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000933 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000934 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
935 } else {
936 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
937 }
938 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000939}
940
941
lrn@chromium.org303ada72010-10-27 09:33:13 +0000942static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000943 ASSERT(args.length() == 1);
944 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000945 Map* old_map = object->map();
946 bool needs_access_checks = old_map->is_access_check_needed();
947 if (needs_access_checks) {
948 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000949 Object* new_map;
950 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
951 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
952 }
ager@chromium.org32912102009-01-16 10:38:43 +0000953
954 Map::cast(new_map)->set_is_access_check_needed(false);
955 object->set_map(Map::cast(new_map));
956 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000957 return needs_access_checks ? Heap::true_value() : Heap::false_value();
958}
959
960
lrn@chromium.org303ada72010-10-27 09:33:13 +0000961static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000962 ASSERT(args.length() == 1);
963 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000964 Map* old_map = object->map();
965 if (!old_map->is_access_check_needed()) {
966 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000967 Object* new_map;
968 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
969 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
970 }
ager@chromium.org32912102009-01-16 10:38:43 +0000971
972 Map::cast(new_map)->set_is_access_check_needed(true);
973 object->set_map(Map::cast(new_map));
974 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000975 return Heap::undefined_value();
976}
977
978
lrn@chromium.org303ada72010-10-27 09:33:13 +0000979static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000980 HandleScope scope;
981 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
982 Handle<Object> args[2] = { type_handle, name };
983 Handle<Object> error =
984 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
985 return Top::Throw(*error);
986}
987
988
lrn@chromium.org303ada72010-10-27 09:33:13 +0000989static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000990 HandleScope scope;
991 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
992
ager@chromium.org3811b432009-10-28 14:53:37 +0000993 Handle<Context> context = args.at<Context>(0);
994 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000995 bool is_eval = Smi::cast(args[2])->value() == 1;
996
997 // Compute the property attributes. According to ECMA-262, section
998 // 13, page 71, the property must be read-only and
999 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1000 // property as read-only, so we don't either.
1001 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1002
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003 // Traverse the name/value pairs and set the properties.
1004 int length = pairs->length();
1005 for (int i = 0; i < length; i += 2) {
1006 HandleScope scope;
1007 Handle<String> name(String::cast(pairs->get(i)));
1008 Handle<Object> value(pairs->get(i + 1));
1009
1010 // We have to declare a global const property. To capture we only
1011 // assign to it when evaluating the assignment for "const x =
1012 // <expr>" the initial value is the hole.
1013 bool is_const_property = value->IsTheHole();
1014
1015 if (value->IsUndefined() || is_const_property) {
1016 // Lookup the property in the global object, and don't set the
1017 // value of the variable if the property is already there.
1018 LookupResult lookup;
1019 global->Lookup(*name, &lookup);
1020 if (lookup.IsProperty()) {
1021 // Determine if the property is local by comparing the holder
1022 // against the global object. The information will be used to
1023 // avoid throwing re-declaration errors when declaring
1024 // variables or constants that exist in the prototype chain.
1025 bool is_local = (*global == lookup.holder());
1026 // Get the property attributes and determine if the property is
1027 // read-only.
1028 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1029 bool is_read_only = (attributes & READ_ONLY) != 0;
1030 if (lookup.type() == INTERCEPTOR) {
1031 // If the interceptor says the property is there, we
1032 // just return undefined without overwriting the property.
1033 // Otherwise, we continue to setting the property.
1034 if (attributes != ABSENT) {
1035 // Check if the existing property conflicts with regards to const.
1036 if (is_local && (is_read_only || is_const_property)) {
1037 const char* type = (is_read_only) ? "const" : "var";
1038 return ThrowRedeclarationError(type, name);
1039 };
1040 // The property already exists without conflicting: Go to
1041 // the next declaration.
1042 continue;
1043 }
1044 // Fall-through and introduce the absent property by using
1045 // SetProperty.
1046 } else {
1047 if (is_local && (is_read_only || is_const_property)) {
1048 const char* type = (is_read_only) ? "const" : "var";
1049 return ThrowRedeclarationError(type, name);
1050 }
1051 // The property already exists without conflicting: Go to
1052 // the next declaration.
1053 continue;
1054 }
1055 }
1056 } else {
1057 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001058 Handle<SharedFunctionInfo> shared =
1059 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001060 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001061 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062 value = function;
1063 }
1064
1065 LookupResult lookup;
1066 global->LocalLookup(*name, &lookup);
1067
1068 PropertyAttributes attributes = is_const_property
1069 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1070 : base;
1071
1072 if (lookup.IsProperty()) {
1073 // There's a local property that we need to overwrite because
1074 // we're either declaring a function or there's an interceptor
1075 // that claims the property is absent.
1076
1077 // Check for conflicting re-declarations. We cannot have
1078 // conflicting types in case of intercepted properties because
1079 // they are absent.
1080 if (lookup.type() != INTERCEPTOR &&
1081 (lookup.IsReadOnly() || is_const_property)) {
1082 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
1083 return ThrowRedeclarationError(type, name);
1084 }
1085 SetProperty(global, name, value, attributes);
1086 } else {
1087 // If a property with this name does not already exist on the
1088 // global object add the property locally. We take special
1089 // precautions to always add it as a local property even in case
1090 // of callbacks in the prototype chain (this rules out using
1091 // SetProperty). Also, we must use the handle-based version to
1092 // avoid GC issues.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001093 SetLocalPropertyIgnoreAttributes(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001094 }
1095 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001096
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001097 return Heap::undefined_value();
1098}
1099
1100
lrn@chromium.org303ada72010-10-27 09:33:13 +00001101static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001103 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001104
ager@chromium.org7c537e22008-10-16 08:43:32 +00001105 CONVERT_ARG_CHECKED(Context, context, 0);
1106 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001107 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001108 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001109 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001110 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111
1112 // Declarations are always done in the function context.
1113 context = Handle<Context>(context->fcontext());
1114
1115 int index;
1116 PropertyAttributes attributes;
1117 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001118 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001119 context->Lookup(name, flags, &index, &attributes);
1120
1121 if (attributes != ABSENT) {
1122 // The name was declared before; check for conflicting
1123 // re-declarations: This is similar to the code in parser.cc in
1124 // the AstBuildingParser::Declare function.
1125 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1126 // Functions are not read-only.
1127 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1128 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1129 return ThrowRedeclarationError(type, name);
1130 }
1131
1132 // Initialize it if necessary.
1133 if (*initial_value != NULL) {
1134 if (index >= 0) {
1135 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001136 // the function context or the arguments object.
1137 if (holder->IsContext()) {
1138 ASSERT(holder.is_identical_to(context));
1139 if (((attributes & READ_ONLY) == 0) ||
1140 context->get(index)->IsTheHole()) {
1141 context->set(index, *initial_value);
1142 }
1143 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001144 // The holder is an arguments object.
1145 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1146 SetElement(arguments, index, initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147 }
1148 } else {
1149 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001150 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 SetProperty(context_ext, name, initial_value, mode);
1152 }
1153 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001154
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001155 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001156 // The property is not in the function context. It needs to be
1157 // "declared" in the function context's extension context, or in the
1158 // global context.
1159 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001160 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001161 // The function context's extension context exists - use it.
1162 context_ext = Handle<JSObject>(context->extension());
1163 } else {
1164 // The function context's extension context does not exists - allocate
1165 // it.
1166 context_ext = Factory::NewJSObject(Top::context_extension_function());
1167 // And store it in the extension slot.
1168 context->set_extension(*context_ext);
1169 }
1170 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001171
ager@chromium.org7c537e22008-10-16 08:43:32 +00001172 // Declare the property by setting it to the initial value if provided,
1173 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1174 // constant declarations).
1175 ASSERT(!context_ext->HasLocalProperty(*name));
1176 Handle<Object> value(Heap::undefined_value());
1177 if (*initial_value != NULL) value = initial_value;
1178 SetProperty(context_ext, name, value, mode);
1179 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
1180 }
1181
1182 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001183}
1184
1185
lrn@chromium.org303ada72010-10-27 09:33:13 +00001186static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001187 NoHandleAllocation nha;
1188
1189 // Determine if we need to assign to the variable if it already
1190 // exists (based on the number of arguments).
1191 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1192 bool assign = args.length() == 2;
1193
1194 CONVERT_ARG_CHECKED(String, name, 0);
1195 GlobalObject* global = Top::context()->global();
1196
1197 // According to ECMA-262, section 12.2, page 62, the property must
1198 // not be deletable.
1199 PropertyAttributes attributes = DONT_DELETE;
1200
1201 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001202 // there, there is a property with this name in the prototype chain.
1203 // We follow Safari and Firefox behavior and only set the property
1204 // locally if there is an explicit initialization value that we have
1205 // to assign to the property. When adding the property we take
1206 // special precautions to always add it as a local property even in
1207 // case of callbacks in the prototype chain (this rules out using
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001208 // SetProperty). We have SetLocalPropertyIgnoreAttributes for
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001209 // this.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001210 // Note that objects can have hidden prototypes, so we need to traverse
1211 // the whole chain of hidden prototypes to do a 'local' lookup.
1212 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001213 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001214 while (true) {
1215 real_holder->LocalLookup(*name, &lookup);
1216 if (lookup.IsProperty()) {
1217 // Determine if this is a redeclaration of something read-only.
1218 if (lookup.IsReadOnly()) {
1219 // If we found readonly property on one of hidden prototypes,
1220 // just shadow it.
1221 if (real_holder != Top::context()->global()) break;
1222 return ThrowRedeclarationError("const", name);
1223 }
1224
1225 // Determine if this is a redeclaration of an intercepted read-only
1226 // property and figure out if the property exists at all.
1227 bool found = true;
1228 PropertyType type = lookup.type();
1229 if (type == INTERCEPTOR) {
1230 HandleScope handle_scope;
1231 Handle<JSObject> holder(real_holder);
1232 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1233 real_holder = *holder;
1234 if (intercepted == ABSENT) {
1235 // The interceptor claims the property isn't there. We need to
1236 // make sure to introduce it.
1237 found = false;
1238 } else if ((intercepted & READ_ONLY) != 0) {
1239 // The property is present, but read-only. Since we're trying to
1240 // overwrite it with a variable declaration we must throw a
1241 // re-declaration error. However if we found readonly property
1242 // on one of hidden prototypes, just shadow it.
1243 if (real_holder != Top::context()->global()) break;
1244 return ThrowRedeclarationError("const", name);
1245 }
1246 }
1247
1248 if (found && !assign) {
1249 // The global property is there and we're not assigning any value
1250 // to it. Just return.
1251 return Heap::undefined_value();
1252 }
1253
1254 // Assign the value (or undefined) to the property.
1255 Object* value = (assign) ? args[1] : Heap::undefined_value();
1256 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001257 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001258
1259 Object* proto = real_holder->GetPrototype();
1260 if (!proto->IsJSObject())
1261 break;
1262
1263 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1264 break;
1265
1266 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267 }
1268
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001269 global = Top::context()->global();
1270 if (assign) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001271 return global->SetLocalPropertyIgnoreAttributes(*name,
1272 args[1],
1273 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001275 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001276}
1277
1278
lrn@chromium.org303ada72010-10-27 09:33:13 +00001279static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280 // All constants are declared with an initial value. The name
1281 // of the constant is the first argument and the initial value
1282 // is the second.
1283 RUNTIME_ASSERT(args.length() == 2);
1284 CONVERT_ARG_CHECKED(String, name, 0);
1285 Handle<Object> value = args.at<Object>(1);
1286
1287 // Get the current global object from top.
1288 GlobalObject* global = Top::context()->global();
1289
1290 // According to ECMA-262, section 12.2, page 62, the property must
1291 // not be deletable. Since it's a const, it must be READ_ONLY too.
1292 PropertyAttributes attributes =
1293 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1294
1295 // Lookup the property locally in the global object. If it isn't
1296 // there, we add the property and take special precautions to always
1297 // add it as a local property even in case of callbacks in the
1298 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001299 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300 LookupResult lookup;
1301 global->LocalLookup(*name, &lookup);
1302 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001303 return global->SetLocalPropertyIgnoreAttributes(*name,
1304 *value,
1305 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001306 }
1307
1308 // Determine if this is a redeclaration of something not
1309 // read-only. In case the result is hidden behind an interceptor we
1310 // need to ask it for the property attributes.
1311 if (!lookup.IsReadOnly()) {
1312 if (lookup.type() != INTERCEPTOR) {
1313 return ThrowRedeclarationError("var", name);
1314 }
1315
1316 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1317
1318 // Throw re-declaration error if the intercepted property is present
1319 // but not read-only.
1320 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1321 return ThrowRedeclarationError("var", name);
1322 }
1323
1324 // Restore global object from context (in case of GC) and continue
1325 // with setting the value because the property is either absent or
1326 // read-only. We also have to do redo the lookup.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001327 HandleScope handle_scope;
1328 Handle<GlobalObject>global(Top::context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329
1330 // BUG 1213579: Handle the case where we have to set a read-only
1331 // property through an interceptor and only do it if it's
1332 // uninitialized, e.g. the hole. Nirk...
lrn@chromium.org303ada72010-10-27 09:33:13 +00001333 SetProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001334 return *value;
1335 }
1336
1337 // Set the value, but only we're assigning the initial value to a
1338 // constant. For now, we determine this by checking if the
1339 // current value is the hole.
1340 PropertyType type = lookup.type();
1341 if (type == FIELD) {
1342 FixedArray* properties = global->properties();
1343 int index = lookup.GetFieldIndex();
1344 if (properties->get(index)->IsTheHole()) {
1345 properties->set(index, *value);
1346 }
1347 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001348 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1349 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001350 }
1351 } else {
1352 // Ignore re-initialization of constants that have already been
1353 // assigned a function value.
1354 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1355 }
1356
1357 // Use the set value as the result of the operation.
1358 return *value;
1359}
1360
1361
lrn@chromium.org303ada72010-10-27 09:33:13 +00001362static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001363 HandleScope scope;
1364 ASSERT(args.length() == 3);
1365
1366 Handle<Object> value(args[0]);
1367 ASSERT(!value->IsTheHole());
1368 CONVERT_ARG_CHECKED(Context, context, 1);
1369 Handle<String> name(String::cast(args[2]));
1370
1371 // Initializations are always done in the function context.
1372 context = Handle<Context>(context->fcontext());
1373
1374 int index;
1375 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001376 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001377 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001378 context->Lookup(name, flags, &index, &attributes);
1379
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001380 // In most situations, the property introduced by the const
1381 // declaration should be present in the context extension object.
1382 // However, because declaration and initialization are separate, the
1383 // property might have been deleted (if it was introduced by eval)
1384 // before we reach the initialization point.
1385 //
1386 // Example:
1387 //
1388 // function f() { eval("delete x; const x;"); }
1389 //
1390 // In that case, the initialization behaves like a normal assignment
1391 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001392 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001393 // Property was found in a context.
1394 if (holder->IsContext()) {
1395 // The holder cannot be the function context. If it is, there
1396 // should have been a const redeclaration error when declaring
1397 // the const property.
1398 ASSERT(!holder.is_identical_to(context));
1399 if ((attributes & READ_ONLY) == 0) {
1400 Handle<Context>::cast(holder)->set(index, *value);
1401 }
1402 } else {
1403 // The holder is an arguments object.
1404 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001405 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1406 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407 }
1408 return *value;
1409 }
1410
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001411 // The property could not be found, we introduce it in the global
1412 // context.
1413 if (attributes == ABSENT) {
1414 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
1415 SetProperty(global, name, value, NONE);
1416 return *value;
1417 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001418
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001419 // The property was present in a context extension object.
1420 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001421
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001422 if (*context_ext == context->extension()) {
1423 // This is the property that was introduced by the const
1424 // declaration. Set it if it hasn't been set before. NOTE: We
1425 // cannot use GetProperty() to get the current value as it
1426 // 'unholes' the value.
1427 LookupResult lookup;
1428 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1429 ASSERT(lookup.IsProperty()); // the property was declared
1430 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1431
1432 PropertyType type = lookup.type();
1433 if (type == FIELD) {
1434 FixedArray* properties = context_ext->properties();
1435 int index = lookup.GetFieldIndex();
1436 if (properties->get(index)->IsTheHole()) {
1437 properties->set(index, *value);
1438 }
1439 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001440 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1441 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001442 }
1443 } else {
1444 // We should not reach here. Any real, named property should be
1445 // either a field or a dictionary slot.
1446 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001447 }
1448 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001449 // The property was found in a different context extension object.
1450 // Set it if it is not a read-only property.
1451 if ((attributes & READ_ONLY) == 0) {
1452 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
1453 // Setting a property might throw an exception. Exceptions
1454 // are converted to empty handles in handle operations. We
1455 // need to convert back to exceptions here.
1456 if (set.is_null()) {
1457 ASSERT(Top::has_pending_exception());
1458 return Failure::Exception();
1459 }
1460 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001461 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001462
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001463 return *value;
1464}
1465
1466
lrn@chromium.org303ada72010-10-27 09:33:13 +00001467static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001468 Arguments args) {
1469 HandleScope scope;
1470 ASSERT(args.length() == 2);
1471 CONVERT_ARG_CHECKED(JSObject, object, 0);
1472 CONVERT_SMI_CHECKED(properties, args[1]);
1473 if (object->HasFastProperties()) {
1474 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1475 }
1476 return *object;
1477}
1478
1479
lrn@chromium.org303ada72010-10-27 09:33:13 +00001480static MaybeObject* Runtime_RegExpExec(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001481 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001482 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001483 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1484 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001485 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001486 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001487 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001488 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001489 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001490 RUNTIME_ASSERT(index >= 0);
1491 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001492 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001493 Handle<Object> result = RegExpImpl::Exec(regexp,
1494 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001495 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001496 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001497 if (result.is_null()) return Failure::Exception();
1498 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001499}
1500
1501
lrn@chromium.org303ada72010-10-27 09:33:13 +00001502static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001503 ASSERT(args.length() == 3);
1504 CONVERT_SMI_CHECKED(elements_count, args[0]);
1505 if (elements_count > JSArray::kMaxFastElementsLength) {
1506 return Top::ThrowIllegalOperation();
1507 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001508 Object* new_object;
1509 { MaybeObject* maybe_new_object =
1510 Heap::AllocateFixedArrayWithHoles(elements_count);
1511 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1512 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001513 FixedArray* elements = FixedArray::cast(new_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001514 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1515 NEW_SPACE,
1516 OLD_POINTER_SPACE);
1517 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1518 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001519 {
1520 AssertNoAllocation no_gc;
1521 HandleScope scope;
1522 reinterpret_cast<HeapObject*>(new_object)->
1523 set_map(Top::global_context()->regexp_result_map());
1524 }
1525 JSArray* array = JSArray::cast(new_object);
1526 array->set_properties(Heap::empty_fixed_array());
1527 array->set_elements(elements);
1528 array->set_length(Smi::FromInt(elements_count));
1529 // Write in-object properties after the length of the array.
1530 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1531 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1532 return array;
1533}
1534
1535
lrn@chromium.org303ada72010-10-27 09:33:13 +00001536static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001537 AssertNoAllocation no_alloc;
1538 ASSERT(args.length() == 5);
1539 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1540 CONVERT_CHECKED(String, source, args[1]);
1541
1542 Object* global = args[2];
1543 if (!global->IsTrue()) global = Heap::false_value();
1544
1545 Object* ignoreCase = args[3];
1546 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1547
1548 Object* multiline = args[4];
1549 if (!multiline->IsTrue()) multiline = Heap::false_value();
1550
1551 Map* map = regexp->map();
1552 Object* constructor = map->constructor();
1553 if (constructor->IsJSFunction() &&
1554 JSFunction::cast(constructor)->initial_map() == map) {
1555 // If we still have the original map, set in-object properties directly.
1556 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1557 // TODO(lrn): Consider skipping write barrier on booleans as well.
1558 // Both true and false should be in oldspace at all times.
1559 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1560 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1561 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1562 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1563 Smi::FromInt(0),
1564 SKIP_WRITE_BARRIER);
1565 return regexp;
1566 }
1567
lrn@chromium.org303ada72010-10-27 09:33:13 +00001568 // Map has changed, so use generic, but slower, method. Since these
1569 // properties were all added as DONT_DELETE they must be present and
1570 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001571 PropertyAttributes final =
1572 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1573 PropertyAttributes writable =
1574 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001575 MaybeObject* result;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001576 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::source_symbol(),
1577 source,
1578 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001579 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001580 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::global_symbol(),
1581 global,
1582 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001583 ASSERT(!result->IsFailure());
1584 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001585 regexp->SetLocalPropertyIgnoreAttributes(Heap::ignore_case_symbol(),
1586 ignoreCase,
1587 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001588 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001589 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::multiline_symbol(),
1590 multiline,
1591 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001592 ASSERT(!result->IsFailure());
1593 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001594 regexp->SetLocalPropertyIgnoreAttributes(Heap::last_index_symbol(),
1595 Smi::FromInt(0),
1596 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001597 ASSERT(!result->IsFailure());
1598 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001599 return regexp;
1600}
1601
1602
lrn@chromium.org303ada72010-10-27 09:33:13 +00001603static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001604 HandleScope scope;
1605 ASSERT(args.length() == 1);
1606 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1607 // This is necessary to enable fast checks for absence of elements
1608 // on Array.prototype and below.
1609 prototype->set_elements(Heap::empty_fixed_array());
1610 return Smi::FromInt(0);
1611}
1612
1613
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001614static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1615 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001616 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001617 Handle<String> key = Factory::LookupAsciiSymbol(name);
1618 Handle<Code> code(Builtins::builtin(builtin_name));
1619 Handle<JSFunction> optimized = Factory::NewFunction(key,
1620 JS_OBJECT_TYPE,
1621 JSObject::kHeaderSize,
1622 code,
1623 false);
1624 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001625 SetProperty(holder, key, optimized, NONE);
1626 return optimized;
1627}
1628
1629
lrn@chromium.org303ada72010-10-27 09:33:13 +00001630static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001631 HandleScope scope;
1632 ASSERT(args.length() == 1);
1633 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1634
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001635 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1636 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001637 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1638 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1639 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1640 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001641 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001642
1643 return *holder;
1644}
1645
1646
lrn@chromium.org303ada72010-10-27 09:33:13 +00001647static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001648 // Returns a real global receiver, not one of builtins object.
1649 Context* global_context = Top::context()->global()->global_context();
1650 return global_context->global()->global_receiver();
1651}
1652
1653
lrn@chromium.org303ada72010-10-27 09:33:13 +00001654static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001655 HandleScope scope;
1656 ASSERT(args.length() == 4);
1657 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1658 int index = Smi::cast(args[1])->value();
1659 Handle<String> pattern = args.at<String>(2);
1660 Handle<String> flags = args.at<String>(3);
1661
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001662 // Get the RegExp function from the context in the literals array.
1663 // This is the RegExp function from the context in which the
1664 // function was created. We do not use the RegExp function from the
1665 // current global context because this might be the RegExp function
1666 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001667 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001668 Handle<JSFunction>(
1669 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001670 // Compute the regular expression literal.
1671 bool has_pending_exception;
1672 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001673 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1674 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001675 if (has_pending_exception) {
1676 ASSERT(Top::has_pending_exception());
1677 return Failure::Exception();
1678 }
1679 literals->set(index, *regexp);
1680 return *regexp;
1681}
1682
1683
lrn@chromium.org303ada72010-10-27 09:33:13 +00001684static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001685 NoHandleAllocation ha;
1686 ASSERT(args.length() == 1);
1687
1688 CONVERT_CHECKED(JSFunction, f, args[0]);
1689 return f->shared()->name();
1690}
1691
1692
lrn@chromium.org303ada72010-10-27 09:33:13 +00001693static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001694 NoHandleAllocation ha;
1695 ASSERT(args.length() == 2);
1696
1697 CONVERT_CHECKED(JSFunction, f, args[0]);
1698 CONVERT_CHECKED(String, name, args[1]);
1699 f->shared()->set_name(name);
1700 return Heap::undefined_value();
1701}
1702
1703
lrn@chromium.org303ada72010-10-27 09:33:13 +00001704static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001705 NoHandleAllocation ha;
1706 ASSERT(args.length() == 1);
1707
1708 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001709 Object* obj;
1710 { MaybeObject* maybe_obj = f->RemovePrototype();
1711 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1712 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001713
1714 return Heap::undefined_value();
1715}
1716
1717
lrn@chromium.org303ada72010-10-27 09:33:13 +00001718static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719 HandleScope scope;
1720 ASSERT(args.length() == 1);
1721
1722 CONVERT_CHECKED(JSFunction, fun, args[0]);
1723 Handle<Object> script = Handle<Object>(fun->shared()->script());
1724 if (!script->IsScript()) return Heap::undefined_value();
1725
1726 return *GetScriptWrapper(Handle<Script>::cast(script));
1727}
1728
1729
lrn@chromium.org303ada72010-10-27 09:33:13 +00001730static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001731 NoHandleAllocation ha;
1732 ASSERT(args.length() == 1);
1733
1734 CONVERT_CHECKED(JSFunction, f, args[0]);
1735 return f->shared()->GetSourceCode();
1736}
1737
1738
lrn@chromium.org303ada72010-10-27 09:33:13 +00001739static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001740 NoHandleAllocation ha;
1741 ASSERT(args.length() == 1);
1742
1743 CONVERT_CHECKED(JSFunction, fun, args[0]);
1744 int pos = fun->shared()->start_position();
1745 return Smi::FromInt(pos);
1746}
1747
1748
lrn@chromium.org303ada72010-10-27 09:33:13 +00001749static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001750 ASSERT(args.length() == 2);
1751
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001752 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001753 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1754
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001755 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1756
1757 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001758 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001759}
1760
1761
1762
lrn@chromium.org303ada72010-10-27 09:33:13 +00001763static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001764 NoHandleAllocation ha;
1765 ASSERT(args.length() == 2);
1766
1767 CONVERT_CHECKED(JSFunction, fun, args[0]);
1768 CONVERT_CHECKED(String, name, args[1]);
1769 fun->SetInstanceClassName(name);
1770 return Heap::undefined_value();
1771}
1772
1773
lrn@chromium.org303ada72010-10-27 09:33:13 +00001774static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001775 NoHandleAllocation ha;
1776 ASSERT(args.length() == 2);
1777
1778 CONVERT_CHECKED(JSFunction, fun, args[0]);
1779 CONVERT_CHECKED(Smi, length, args[1]);
1780 fun->shared()->set_length(length->value());
1781 return length;
1782}
1783
1784
lrn@chromium.org303ada72010-10-27 09:33:13 +00001785static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001786 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001787 ASSERT(args.length() == 2);
1788
1789 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001790 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001791 Object* obj;
1792 { MaybeObject* maybe_obj =
1793 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1794 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1795 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001796 return args[0]; // return TOS
1797}
1798
1799
lrn@chromium.org303ada72010-10-27 09:33:13 +00001800static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001801 NoHandleAllocation ha;
1802 ASSERT(args.length() == 1);
1803
1804 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001805 return f->shared()->IsApiFunction() ? Heap::true_value()
1806 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001807}
1808
lrn@chromium.org303ada72010-10-27 09:33:13 +00001809static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001810 NoHandleAllocation ha;
1811 ASSERT(args.length() == 1);
1812
1813 CONVERT_CHECKED(JSFunction, f, args[0]);
1814 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1815}
1816
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001817
lrn@chromium.org303ada72010-10-27 09:33:13 +00001818static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001819 HandleScope scope;
1820 ASSERT(args.length() == 2);
1821
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001822 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001823 Handle<Object> code = args.at<Object>(1);
1824
1825 Handle<Context> context(target->context());
1826
1827 if (!code->IsNull()) {
1828 RUNTIME_ASSERT(code->IsJSFunction());
1829 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001830 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001831
1832 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001833 return Failure::Exception();
1834 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001835 // Since we don't store the source for this we should never
1836 // optimize this.
1837 shared->code()->set_optimizable(false);
1838
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001839 // Set the code, scope info, formal parameter count,
1840 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001841 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001842 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001843 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001844 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001845 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001846 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001847 // Set the source code of the target function to undefined.
1848 // SetCode is only used for built-in constructors like String,
1849 // Array, and Object, and some web code
1850 // doesn't like seeing source code for constructors.
1851 target->shared()->set_script(Heap::undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001852 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001853 // Clear the optimization hints related to the compiled code as these are no
1854 // longer valid when the code is overwritten.
1855 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001856 context = Handle<Context>(fun->context());
1857
1858 // Make sure we get a fresh copy of the literal vector to avoid
1859 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001860 int number_of_literals = fun->NumberOfLiterals();
1861 Handle<FixedArray> literals =
1862 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001863 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001864 // Insert the object, regexp and array functions in the literals
1865 // array prefix. These are the functions that will be used when
1866 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001867 literals->set(JSFunction::kLiteralGlobalContextIndex,
1868 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001870 // It's okay to skip the write barrier here because the literals
1871 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001872 target->set_literals(*literals, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001873 target->set_next_function_link(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001874 }
1875
1876 target->set_context(*context);
1877 return *target;
1878}
1879
1880
lrn@chromium.org303ada72010-10-27 09:33:13 +00001881static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001882 HandleScope scope;
1883 ASSERT(args.length() == 2);
1884 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1885 CONVERT_SMI_CHECKED(num, args[1]);
1886 RUNTIME_ASSERT(num >= 0);
1887 SetExpectedNofProperties(function, num);
1888 return Heap::undefined_value();
1889}
1890
1891
lrn@chromium.org303ada72010-10-27 09:33:13 +00001892MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001893 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001894 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001895 if (code <= 0xffff) {
1896 return Heap::LookupSingleCharacterStringFromCode(code);
1897 }
1898 }
1899 return Heap::empty_string();
1900}
1901
1902
lrn@chromium.org303ada72010-10-27 09:33:13 +00001903static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001904 NoHandleAllocation ha;
1905 ASSERT(args.length() == 2);
1906
1907 CONVERT_CHECKED(String, subject, args[0]);
1908 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001909 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001910
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001911 uint32_t i = 0;
1912 if (index->IsSmi()) {
1913 int value = Smi::cast(index)->value();
1914 if (value < 0) return Heap::nan_value();
1915 i = value;
1916 } else {
1917 ASSERT(index->IsHeapNumber());
1918 double value = HeapNumber::cast(index)->value();
1919 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001920 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001921
1922 // Flatten the string. If someone wants to get a char at an index
1923 // in a cons string, it is likely that more indices will be
1924 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001925 Object* flat;
1926 { MaybeObject* maybe_flat = subject->TryFlatten();
1927 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
1928 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001929 subject = String::cast(flat);
1930
1931 if (i >= static_cast<uint32_t>(subject->length())) {
1932 return Heap::nan_value();
1933 }
1934
1935 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001936}
1937
1938
lrn@chromium.org303ada72010-10-27 09:33:13 +00001939static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001940 NoHandleAllocation ha;
1941 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001942 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001943}
1944
lrn@chromium.org25156de2010-04-06 13:10:27 +00001945
1946class FixedArrayBuilder {
1947 public:
1948 explicit FixedArrayBuilder(int initial_capacity)
1949 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1950 length_(0) {
1951 // Require a non-zero initial size. Ensures that doubling the size to
1952 // extend the array will work.
1953 ASSERT(initial_capacity > 0);
1954 }
1955
1956 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1957 : array_(backing_store),
1958 length_(0) {
1959 // Require a non-zero initial size. Ensures that doubling the size to
1960 // extend the array will work.
1961 ASSERT(backing_store->length() > 0);
1962 }
1963
1964 bool HasCapacity(int elements) {
1965 int length = array_->length();
1966 int required_length = length_ + elements;
1967 return (length >= required_length);
1968 }
1969
1970 void EnsureCapacity(int elements) {
1971 int length = array_->length();
1972 int required_length = length_ + elements;
1973 if (length < required_length) {
1974 int new_length = length;
1975 do {
1976 new_length *= 2;
1977 } while (new_length < required_length);
1978 Handle<FixedArray> extended_array =
1979 Factory::NewFixedArrayWithHoles(new_length);
1980 array_->CopyTo(0, *extended_array, 0, length_);
1981 array_ = extended_array;
1982 }
1983 }
1984
1985 void Add(Object* value) {
1986 ASSERT(length_ < capacity());
1987 array_->set(length_, value);
1988 length_++;
1989 }
1990
1991 void Add(Smi* value) {
1992 ASSERT(length_ < capacity());
1993 array_->set(length_, value);
1994 length_++;
1995 }
1996
1997 Handle<FixedArray> array() {
1998 return array_;
1999 }
2000
2001 int length() {
2002 return length_;
2003 }
2004
2005 int capacity() {
2006 return array_->length();
2007 }
2008
2009 Handle<JSArray> ToJSArray() {
2010 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
2011 result_array->set_length(Smi::FromInt(length_));
2012 return result_array;
2013 }
2014
2015 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2016 target_array->set_elements(*array_);
2017 target_array->set_length(Smi::FromInt(length_));
2018 return target_array;
2019 }
2020
2021 private:
2022 Handle<FixedArray> array_;
2023 int length_;
2024};
2025
2026
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002027// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002028const int kStringBuilderConcatHelperLengthBits = 11;
2029const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002030
2031template <typename schar>
2032static inline void StringBuilderConcatHelper(String*,
2033 schar*,
2034 FixedArray*,
2035 int);
2036
lrn@chromium.org25156de2010-04-06 13:10:27 +00002037typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2038 StringBuilderSubstringLength;
2039typedef BitField<int,
2040 kStringBuilderConcatHelperLengthBits,
2041 kStringBuilderConcatHelperPositionBits>
2042 StringBuilderSubstringPosition;
2043
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002044
2045class ReplacementStringBuilder {
2046 public:
2047 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00002048 : array_builder_(estimated_part_count),
2049 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002050 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002051 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002052 // Require a non-zero initial size. Ensures that doubling the size to
2053 // extend the array will work.
2054 ASSERT(estimated_part_count > 0);
2055 }
2056
lrn@chromium.org25156de2010-04-06 13:10:27 +00002057 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2058 int from,
2059 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002060 ASSERT(from >= 0);
2061 int length = to - from;
2062 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002063 if (StringBuilderSubstringLength::is_valid(length) &&
2064 StringBuilderSubstringPosition::is_valid(from)) {
2065 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2066 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002067 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002068 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002069 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002070 builder->Add(Smi::FromInt(-length));
2071 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002072 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002073 }
2074
2075
2076 void EnsureCapacity(int elements) {
2077 array_builder_.EnsureCapacity(elements);
2078 }
2079
2080
2081 void AddSubjectSlice(int from, int to) {
2082 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002083 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002084 }
2085
2086
2087 void AddString(Handle<String> string) {
2088 int length = string->length();
2089 ASSERT(length > 0);
2090 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002091 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002092 is_ascii_ = false;
2093 }
2094 IncrementCharacterCount(length);
2095 }
2096
2097
2098 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002099 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002100 return Factory::empty_string();
2101 }
2102
2103 Handle<String> joined_string;
2104 if (is_ascii_) {
2105 joined_string = NewRawAsciiString(character_count_);
2106 AssertNoAllocation no_alloc;
2107 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2108 char* char_buffer = seq->GetChars();
2109 StringBuilderConcatHelper(*subject_,
2110 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002111 *array_builder_.array(),
2112 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002113 } else {
2114 // Non-ASCII.
2115 joined_string = NewRawTwoByteString(character_count_);
2116 AssertNoAllocation no_alloc;
2117 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2118 uc16* char_buffer = seq->GetChars();
2119 StringBuilderConcatHelper(*subject_,
2120 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002121 *array_builder_.array(),
2122 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002123 }
2124 return joined_string;
2125 }
2126
2127
2128 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002129 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002130 V8::FatalProcessOutOfMemory("String.replace result too large.");
2131 }
2132 character_count_ += by;
2133 }
2134
lrn@chromium.org25156de2010-04-06 13:10:27 +00002135 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002136 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002137 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002138
lrn@chromium.org25156de2010-04-06 13:10:27 +00002139 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002140 Handle<String> NewRawAsciiString(int size) {
2141 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2142 }
2143
2144
2145 Handle<String> NewRawTwoByteString(int size) {
2146 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2147 }
2148
2149
2150 void AddElement(Object* element) {
2151 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002152 ASSERT(array_builder_.capacity() > array_builder_.length());
2153 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002154 }
2155
lrn@chromium.org25156de2010-04-06 13:10:27 +00002156 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002157 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002158 int character_count_;
2159 bool is_ascii_;
2160};
2161
2162
2163class CompiledReplacement {
2164 public:
2165 CompiledReplacement()
2166 : parts_(1), replacement_substrings_(0) {}
2167
2168 void Compile(Handle<String> replacement,
2169 int capture_count,
2170 int subject_length);
2171
2172 void Apply(ReplacementStringBuilder* builder,
2173 int match_from,
2174 int match_to,
2175 Handle<JSArray> last_match_info);
2176
2177 // Number of distinct parts of the replacement pattern.
2178 int parts() {
2179 return parts_.length();
2180 }
2181 private:
2182 enum PartType {
2183 SUBJECT_PREFIX = 1,
2184 SUBJECT_SUFFIX,
2185 SUBJECT_CAPTURE,
2186 REPLACEMENT_SUBSTRING,
2187 REPLACEMENT_STRING,
2188
2189 NUMBER_OF_PART_TYPES
2190 };
2191
2192 struct ReplacementPart {
2193 static inline ReplacementPart SubjectMatch() {
2194 return ReplacementPart(SUBJECT_CAPTURE, 0);
2195 }
2196 static inline ReplacementPart SubjectCapture(int capture_index) {
2197 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2198 }
2199 static inline ReplacementPart SubjectPrefix() {
2200 return ReplacementPart(SUBJECT_PREFIX, 0);
2201 }
2202 static inline ReplacementPart SubjectSuffix(int subject_length) {
2203 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2204 }
2205 static inline ReplacementPart ReplacementString() {
2206 return ReplacementPart(REPLACEMENT_STRING, 0);
2207 }
2208 static inline ReplacementPart ReplacementSubString(int from, int to) {
2209 ASSERT(from >= 0);
2210 ASSERT(to > from);
2211 return ReplacementPart(-from, to);
2212 }
2213
2214 // If tag <= 0 then it is the negation of a start index of a substring of
2215 // the replacement pattern, otherwise it's a value from PartType.
2216 ReplacementPart(int tag, int data)
2217 : tag(tag), data(data) {
2218 // Must be non-positive or a PartType value.
2219 ASSERT(tag < NUMBER_OF_PART_TYPES);
2220 }
2221 // Either a value of PartType or a non-positive number that is
2222 // the negation of an index into the replacement string.
2223 int tag;
2224 // The data value's interpretation depends on the value of tag:
2225 // tag == SUBJECT_PREFIX ||
2226 // tag == SUBJECT_SUFFIX: data is unused.
2227 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2228 // tag == REPLACEMENT_SUBSTRING ||
2229 // tag == REPLACEMENT_STRING: data is index into array of substrings
2230 // of the replacement string.
2231 // tag <= 0: Temporary representation of the substring of the replacement
2232 // string ranging over -tag .. data.
2233 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2234 // substring objects.
2235 int data;
2236 };
2237
2238 template<typename Char>
2239 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2240 Vector<Char> characters,
2241 int capture_count,
2242 int subject_length) {
2243 int length = characters.length();
2244 int last = 0;
2245 for (int i = 0; i < length; i++) {
2246 Char c = characters[i];
2247 if (c == '$') {
2248 int next_index = i + 1;
2249 if (next_index == length) { // No next character!
2250 break;
2251 }
2252 Char c2 = characters[next_index];
2253 switch (c2) {
2254 case '$':
2255 if (i > last) {
2256 // There is a substring before. Include the first "$".
2257 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2258 last = next_index + 1; // Continue after the second "$".
2259 } else {
2260 // Let the next substring start with the second "$".
2261 last = next_index;
2262 }
2263 i = next_index;
2264 break;
2265 case '`':
2266 if (i > last) {
2267 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2268 }
2269 parts->Add(ReplacementPart::SubjectPrefix());
2270 i = next_index;
2271 last = i + 1;
2272 break;
2273 case '\'':
2274 if (i > last) {
2275 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2276 }
2277 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2278 i = next_index;
2279 last = i + 1;
2280 break;
2281 case '&':
2282 if (i > last) {
2283 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2284 }
2285 parts->Add(ReplacementPart::SubjectMatch());
2286 i = next_index;
2287 last = i + 1;
2288 break;
2289 case '0':
2290 case '1':
2291 case '2':
2292 case '3':
2293 case '4':
2294 case '5':
2295 case '6':
2296 case '7':
2297 case '8':
2298 case '9': {
2299 int capture_ref = c2 - '0';
2300 if (capture_ref > capture_count) {
2301 i = next_index;
2302 continue;
2303 }
2304 int second_digit_index = next_index + 1;
2305 if (second_digit_index < length) {
2306 // Peek ahead to see if we have two digits.
2307 Char c3 = characters[second_digit_index];
2308 if ('0' <= c3 && c3 <= '9') { // Double digits.
2309 int double_digit_ref = capture_ref * 10 + c3 - '0';
2310 if (double_digit_ref <= capture_count) {
2311 next_index = second_digit_index;
2312 capture_ref = double_digit_ref;
2313 }
2314 }
2315 }
2316 if (capture_ref > 0) {
2317 if (i > last) {
2318 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2319 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002320 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002321 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2322 last = next_index + 1;
2323 }
2324 i = next_index;
2325 break;
2326 }
2327 default:
2328 i = next_index;
2329 break;
2330 }
2331 }
2332 }
2333 if (length > last) {
2334 if (last == 0) {
2335 parts->Add(ReplacementPart::ReplacementString());
2336 } else {
2337 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2338 }
2339 }
2340 }
2341
2342 ZoneList<ReplacementPart> parts_;
2343 ZoneList<Handle<String> > replacement_substrings_;
2344};
2345
2346
2347void CompiledReplacement::Compile(Handle<String> replacement,
2348 int capture_count,
2349 int subject_length) {
2350 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002351 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002352 AssertNoAllocation no_alloc;
2353 ParseReplacementPattern(&parts_,
2354 replacement->ToAsciiVector(),
2355 capture_count,
2356 subject_length);
2357 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002358 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002359 AssertNoAllocation no_alloc;
2360
2361 ParseReplacementPattern(&parts_,
2362 replacement->ToUC16Vector(),
2363 capture_count,
2364 subject_length);
2365 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002366 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002367 int substring_index = 0;
2368 for (int i = 0, n = parts_.length(); i < n; i++) {
2369 int tag = parts_[i].tag;
2370 if (tag <= 0) { // A replacement string slice.
2371 int from = -tag;
2372 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002373 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002374 parts_[i].tag = REPLACEMENT_SUBSTRING;
2375 parts_[i].data = substring_index;
2376 substring_index++;
2377 } else if (tag == REPLACEMENT_STRING) {
2378 replacement_substrings_.Add(replacement);
2379 parts_[i].data = substring_index;
2380 substring_index++;
2381 }
2382 }
2383}
2384
2385
2386void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2387 int match_from,
2388 int match_to,
2389 Handle<JSArray> last_match_info) {
2390 for (int i = 0, n = parts_.length(); i < n; i++) {
2391 ReplacementPart part = parts_[i];
2392 switch (part.tag) {
2393 case SUBJECT_PREFIX:
2394 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2395 break;
2396 case SUBJECT_SUFFIX: {
2397 int subject_length = part.data;
2398 if (match_to < subject_length) {
2399 builder->AddSubjectSlice(match_to, subject_length);
2400 }
2401 break;
2402 }
2403 case SUBJECT_CAPTURE: {
2404 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002405 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002406 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2407 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2408 if (from >= 0 && to > from) {
2409 builder->AddSubjectSlice(from, to);
2410 }
2411 break;
2412 }
2413 case REPLACEMENT_SUBSTRING:
2414 case REPLACEMENT_STRING:
2415 builder->AddString(replacement_substrings_[part.data]);
2416 break;
2417 default:
2418 UNREACHABLE();
2419 }
2420 }
2421}
2422
2423
2424
lrn@chromium.org303ada72010-10-27 09:33:13 +00002425MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2426 String* subject,
2427 JSRegExp* regexp,
2428 String* replacement,
2429 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002430 ASSERT(subject->IsFlat());
2431 ASSERT(replacement->IsFlat());
2432
2433 HandleScope handles;
2434
2435 int length = subject->length();
2436 Handle<String> subject_handle(subject);
2437 Handle<JSRegExp> regexp_handle(regexp);
2438 Handle<String> replacement_handle(replacement);
2439 Handle<JSArray> last_match_info_handle(last_match_info);
2440 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2441 subject_handle,
2442 0,
2443 last_match_info_handle);
2444 if (match.is_null()) {
2445 return Failure::Exception();
2446 }
2447 if (match->IsNull()) {
2448 return *subject_handle;
2449 }
2450
2451 int capture_count = regexp_handle->CaptureCount();
2452
2453 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002454 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002455 CompiledReplacement compiled_replacement;
2456 compiled_replacement.Compile(replacement_handle,
2457 capture_count,
2458 length);
2459
2460 bool is_global = regexp_handle->GetFlags().is_global();
2461
2462 // Guessing the number of parts that the final result string is built
2463 // from. Global regexps can match any number of times, so we guess
2464 // conservatively.
2465 int expected_parts =
2466 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2467 ReplacementStringBuilder builder(subject_handle, expected_parts);
2468
2469 // Index of end of last match.
2470 int prev = 0;
2471
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002472 // Number of parts added by compiled replacement plus preceeding
2473 // string and possibly suffix after last match. It is possible for
2474 // all components to use two elements when encoded as two smis.
2475 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002476 bool matched = true;
2477 do {
2478 ASSERT(last_match_info_handle->HasFastElements());
2479 // Increase the capacity of the builder before entering local handle-scope,
2480 // so its internal buffer can safely allocate a new handle if it grows.
2481 builder.EnsureCapacity(parts_added_per_loop);
2482
2483 HandleScope loop_scope;
2484 int start, end;
2485 {
2486 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002487 FixedArray* match_info_array =
2488 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002489
2490 ASSERT_EQ(capture_count * 2 + 2,
2491 RegExpImpl::GetLastCaptureCount(match_info_array));
2492 start = RegExpImpl::GetCapture(match_info_array, 0);
2493 end = RegExpImpl::GetCapture(match_info_array, 1);
2494 }
2495
2496 if (prev < start) {
2497 builder.AddSubjectSlice(prev, start);
2498 }
2499 compiled_replacement.Apply(&builder,
2500 start,
2501 end,
2502 last_match_info_handle);
2503 prev = end;
2504
2505 // Only continue checking for global regexps.
2506 if (!is_global) break;
2507
2508 // Continue from where the match ended, unless it was an empty match.
2509 int next = end;
2510 if (start == end) {
2511 next = end + 1;
2512 if (next > length) break;
2513 }
2514
2515 match = RegExpImpl::Exec(regexp_handle,
2516 subject_handle,
2517 next,
2518 last_match_info_handle);
2519 if (match.is_null()) {
2520 return Failure::Exception();
2521 }
2522 matched = !match->IsNull();
2523 } while (matched);
2524
2525 if (prev < length) {
2526 builder.AddSubjectSlice(prev, length);
2527 }
2528
2529 return *(builder.ToString());
2530}
2531
2532
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002533template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002534MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2535 String* subject,
2536 JSRegExp* regexp,
2537 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002538 ASSERT(subject->IsFlat());
2539
2540 HandleScope handles;
2541
2542 Handle<String> subject_handle(subject);
2543 Handle<JSRegExp> regexp_handle(regexp);
2544 Handle<JSArray> last_match_info_handle(last_match_info);
2545 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2546 subject_handle,
2547 0,
2548 last_match_info_handle);
2549 if (match.is_null()) return Failure::Exception();
2550 if (match->IsNull()) return *subject_handle;
2551
2552 ASSERT(last_match_info_handle->HasFastElements());
2553
2554 HandleScope loop_scope;
2555 int start, end;
2556 {
2557 AssertNoAllocation match_info_array_is_not_in_a_handle;
2558 FixedArray* match_info_array =
2559 FixedArray::cast(last_match_info_handle->elements());
2560
2561 start = RegExpImpl::GetCapture(match_info_array, 0);
2562 end = RegExpImpl::GetCapture(match_info_array, 1);
2563 }
2564
2565 int length = subject->length();
2566 int new_length = length - (end - start);
2567 if (new_length == 0) {
2568 return Heap::empty_string();
2569 }
2570 Handle<ResultSeqString> answer;
2571 if (ResultSeqString::kHasAsciiEncoding) {
2572 answer =
2573 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2574 } else {
2575 answer =
2576 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2577 }
2578
2579 // If the regexp isn't global, only match once.
2580 if (!regexp_handle->GetFlags().is_global()) {
2581 if (start > 0) {
2582 String::WriteToFlat(*subject_handle,
2583 answer->GetChars(),
2584 0,
2585 start);
2586 }
2587 if (end < length) {
2588 String::WriteToFlat(*subject_handle,
2589 answer->GetChars() + start,
2590 end,
2591 length);
2592 }
2593 return *answer;
2594 }
2595
2596 int prev = 0; // Index of end of last match.
2597 int next = 0; // Start of next search (prev unless last match was empty).
2598 int position = 0;
2599
2600 do {
2601 if (prev < start) {
2602 // Add substring subject[prev;start] to answer string.
2603 String::WriteToFlat(*subject_handle,
2604 answer->GetChars() + position,
2605 prev,
2606 start);
2607 position += start - prev;
2608 }
2609 prev = end;
2610 next = end;
2611 // Continue from where the match ended, unless it was an empty match.
2612 if (start == end) {
2613 next++;
2614 if (next > length) break;
2615 }
2616 match = RegExpImpl::Exec(regexp_handle,
2617 subject_handle,
2618 next,
2619 last_match_info_handle);
2620 if (match.is_null()) return Failure::Exception();
2621 if (match->IsNull()) break;
2622
2623 ASSERT(last_match_info_handle->HasFastElements());
2624 HandleScope loop_scope;
2625 {
2626 AssertNoAllocation match_info_array_is_not_in_a_handle;
2627 FixedArray* match_info_array =
2628 FixedArray::cast(last_match_info_handle->elements());
2629 start = RegExpImpl::GetCapture(match_info_array, 0);
2630 end = RegExpImpl::GetCapture(match_info_array, 1);
2631 }
2632 } while (true);
2633
2634 if (prev < length) {
2635 // Add substring subject[prev;length] to answer string.
2636 String::WriteToFlat(*subject_handle,
2637 answer->GetChars() + position,
2638 prev,
2639 length);
2640 position += length - prev;
2641 }
2642
2643 if (position == 0) {
2644 return Heap::empty_string();
2645 }
2646
2647 // Shorten string and fill
2648 int string_size = ResultSeqString::SizeFor(position);
2649 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2650 int delta = allocated_string_size - string_size;
2651
2652 answer->set_length(position);
2653 if (delta == 0) return *answer;
2654
2655 Address end_of_string = answer->address() + string_size;
2656 Heap::CreateFillerObjectAt(end_of_string, delta);
2657
2658 return *answer;
2659}
2660
2661
lrn@chromium.org303ada72010-10-27 09:33:13 +00002662static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002663 ASSERT(args.length() == 4);
2664
2665 CONVERT_CHECKED(String, subject, args[0]);
2666 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002667 Object* flat_subject;
2668 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2669 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2670 return maybe_flat_subject;
2671 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002672 }
2673 subject = String::cast(flat_subject);
2674 }
2675
2676 CONVERT_CHECKED(String, replacement, args[2]);
2677 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002678 Object* flat_replacement;
2679 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2680 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2681 return maybe_flat_replacement;
2682 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002683 }
2684 replacement = String::cast(flat_replacement);
2685 }
2686
2687 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2688 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2689
2690 ASSERT(last_match_info->HasFastElements());
2691
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002692 if (replacement->length() == 0) {
2693 if (subject->HasOnlyAsciiChars()) {
2694 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2695 subject, regexp, last_match_info);
2696 } else {
2697 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2698 subject, regexp, last_match_info);
2699 }
2700 }
2701
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002702 return StringReplaceRegExpWithString(subject,
2703 regexp,
2704 replacement,
2705 last_match_info);
2706}
2707
2708
ager@chromium.org7c537e22008-10-16 08:43:32 +00002709// Perform string match of pattern on subject, starting at start index.
2710// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002711// and should check that pat->length() + start_index <= sub->length().
ager@chromium.org7c537e22008-10-16 08:43:32 +00002712int Runtime::StringMatch(Handle<String> sub,
2713 Handle<String> pat,
2714 int start_index) {
2715 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002716 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002717
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002718 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002719 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002720
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002721 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002722 if (start_index + pattern_length > subject_length) return -1;
2723
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002724 if (!sub->IsFlat()) FlattenString(sub);
2725 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002726
ager@chromium.org7c537e22008-10-16 08:43:32 +00002727 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002728 // Extract flattened substrings of cons strings before determining asciiness.
2729 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002730 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002731 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002732 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002733
ager@chromium.org7c537e22008-10-16 08:43:32 +00002734 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002735 if (seq_pat->IsAsciiRepresentation()) {
2736 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2737 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002738 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002739 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002740 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002741 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002742 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2743 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002744 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002745 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002746 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002747}
2748
2749
lrn@chromium.org303ada72010-10-27 09:33:13 +00002750static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002751 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002752 ASSERT(args.length() == 3);
2753
ager@chromium.org7c537e22008-10-16 08:43:32 +00002754 CONVERT_ARG_CHECKED(String, sub, 0);
2755 CONVERT_ARG_CHECKED(String, pat, 1);
2756
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002757 Object* index = args[2];
2758 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002759 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002760
ager@chromium.org870a0b62008-11-04 11:43:05 +00002761 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002762 int position = Runtime::StringMatch(sub, pat, start_index);
2763 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002764}
2765
2766
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002767template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002768static int StringMatchBackwards(Vector<const schar> subject,
2769 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002770 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002771 int pattern_length = pattern.length();
2772 ASSERT(pattern_length >= 1);
2773 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002774
2775 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002776 for (int i = 0; i < pattern_length; i++) {
2777 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002778 if (c > String::kMaxAsciiCharCode) {
2779 return -1;
2780 }
2781 }
2782 }
2783
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002784 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002785 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002786 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002787 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002788 while (j < pattern_length) {
2789 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002790 break;
2791 }
2792 j++;
2793 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002794 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002795 return i;
2796 }
2797 }
2798 return -1;
2799}
2800
lrn@chromium.org303ada72010-10-27 09:33:13 +00002801static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002802 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002803 ASSERT(args.length() == 3);
2804
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002805 CONVERT_ARG_CHECKED(String, sub, 0);
2806 CONVERT_ARG_CHECKED(String, pat, 1);
2807
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002808 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002809 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002810 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002811
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002812 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002813 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002814
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002815 if (start_index + pat_length > sub_length) {
2816 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002817 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002818
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002819 if (pat_length == 0) {
2820 return Smi::FromInt(start_index);
2821 }
2822
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002823 if (!sub->IsFlat()) FlattenString(sub);
2824 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002825
2826 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2827
2828 int position = -1;
2829
2830 if (pat->IsAsciiRepresentation()) {
2831 Vector<const char> pat_vector = pat->ToAsciiVector();
2832 if (sub->IsAsciiRepresentation()) {
2833 position = StringMatchBackwards(sub->ToAsciiVector(),
2834 pat_vector,
2835 start_index);
2836 } else {
2837 position = StringMatchBackwards(sub->ToUC16Vector(),
2838 pat_vector,
2839 start_index);
2840 }
2841 } else {
2842 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2843 if (sub->IsAsciiRepresentation()) {
2844 position = StringMatchBackwards(sub->ToAsciiVector(),
2845 pat_vector,
2846 start_index);
2847 } else {
2848 position = StringMatchBackwards(sub->ToUC16Vector(),
2849 pat_vector,
2850 start_index);
2851 }
2852 }
2853
2854 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002855}
2856
2857
lrn@chromium.org303ada72010-10-27 09:33:13 +00002858static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002859 NoHandleAllocation ha;
2860 ASSERT(args.length() == 2);
2861
2862 CONVERT_CHECKED(String, str1, args[0]);
2863 CONVERT_CHECKED(String, str2, args[1]);
2864
2865 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002866 int str1_length = str1->length();
2867 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002868
2869 // Decide trivial cases without flattening.
2870 if (str1_length == 0) {
2871 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2872 return Smi::FromInt(-str2_length);
2873 } else {
2874 if (str2_length == 0) return Smi::FromInt(str1_length);
2875 }
2876
2877 int end = str1_length < str2_length ? str1_length : str2_length;
2878
2879 // No need to flatten if we are going to find the answer on the first
2880 // character. At this point we know there is at least one character
2881 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002882 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002883 if (d != 0) return Smi::FromInt(d);
2884
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002885 str1->TryFlatten();
2886 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002887
2888 static StringInputBuffer buf1;
2889 static StringInputBuffer buf2;
2890
2891 buf1.Reset(str1);
2892 buf2.Reset(str2);
2893
2894 for (int i = 0; i < end; i++) {
2895 uint16_t char1 = buf1.GetNext();
2896 uint16_t char2 = buf2.GetNext();
2897 if (char1 != char2) return Smi::FromInt(char1 - char2);
2898 }
2899
2900 return Smi::FromInt(str1_length - str2_length);
2901}
2902
2903
lrn@chromium.org303ada72010-10-27 09:33:13 +00002904static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002905 NoHandleAllocation ha;
2906 ASSERT(args.length() == 3);
2907
2908 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002909 Object* from = args[1];
2910 Object* to = args[2];
2911 int start, end;
2912 // We have a fast integer-only case here to avoid a conversion to double in
2913 // the common case where from and to are Smis.
2914 if (from->IsSmi() && to->IsSmi()) {
2915 start = Smi::cast(from)->value();
2916 end = Smi::cast(to)->value();
2917 } else {
2918 CONVERT_DOUBLE_CHECKED(from_number, from);
2919 CONVERT_DOUBLE_CHECKED(to_number, to);
2920 start = FastD2I(from_number);
2921 end = FastD2I(to_number);
2922 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002923 RUNTIME_ASSERT(end >= start);
2924 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002925 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002926 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002927 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002928}
2929
2930
lrn@chromium.org303ada72010-10-27 09:33:13 +00002931static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002932 ASSERT_EQ(3, args.length());
2933
2934 CONVERT_ARG_CHECKED(String, subject, 0);
2935 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2936 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2937 HandleScope handles;
2938
2939 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2940
2941 if (match.is_null()) {
2942 return Failure::Exception();
2943 }
2944 if (match->IsNull()) {
2945 return Heap::null_value();
2946 }
2947 int length = subject->length();
2948
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002949 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002950 ZoneList<int> offsets(8);
2951 do {
2952 int start;
2953 int end;
2954 {
2955 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002956 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002957 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2958 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2959 }
2960 offsets.Add(start);
2961 offsets.Add(end);
2962 int index = start < end ? end : end + 1;
2963 if (index > length) break;
2964 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2965 if (match.is_null()) {
2966 return Failure::Exception();
2967 }
2968 } while (!match->IsNull());
2969 int matches = offsets.length() / 2;
2970 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2971 for (int i = 0; i < matches ; i++) {
2972 int from = offsets.at(i * 2);
2973 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002974 Handle<String> match = Factory::NewSubString(subject, from, to);
2975 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00002976 }
2977 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2978 result->set_length(Smi::FromInt(matches));
2979 return *result;
2980}
2981
2982
lrn@chromium.org25156de2010-04-06 13:10:27 +00002983// Two smis before and after the match, for very long strings.
2984const int kMaxBuilderEntriesPerRegExpMatch = 5;
2985
2986
2987static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2988 Handle<JSArray> last_match_info,
2989 int match_start,
2990 int match_end) {
2991 // Fill last_match_info with a single capture.
2992 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2993 AssertNoAllocation no_gc;
2994 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2995 RegExpImpl::SetLastCaptureCount(elements, 2);
2996 RegExpImpl::SetLastInput(elements, *subject);
2997 RegExpImpl::SetLastSubject(elements, *subject);
2998 RegExpImpl::SetCapture(elements, 0, match_start);
2999 RegExpImpl::SetCapture(elements, 1, match_end);
3000}
3001
3002
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003003template <typename SubjectChar, typename PatternChar>
3004static bool SearchStringMultiple(Vector<const SubjectChar> subject,
3005 Vector<const PatternChar> pattern,
3006 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003007 FixedArrayBuilder* builder,
3008 int* match_pos) {
3009 int pos = *match_pos;
3010 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003011 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003012 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003013 StringSearch<PatternChar, SubjectChar> search(pattern);
3014 while (pos <= max_search_start) {
3015 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3016 *match_pos = pos;
3017 return false;
3018 }
3019 // Position of end of previous match.
3020 int match_end = pos + pattern_length;
3021 int new_pos = search.Search(subject, match_end);
3022 if (new_pos >= 0) {
3023 // A match.
3024 if (new_pos > match_end) {
3025 ReplacementStringBuilder::AddSubjectSlice(builder,
3026 match_end,
3027 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003028 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003029 pos = new_pos;
3030 builder->Add(pattern_string);
3031 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003032 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003033 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003034 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003035
lrn@chromium.org25156de2010-04-06 13:10:27 +00003036 if (pos < max_search_start) {
3037 ReplacementStringBuilder::AddSubjectSlice(builder,
3038 pos + pattern_length,
3039 subject_length);
3040 }
3041 *match_pos = pos;
3042 return true;
3043}
3044
3045
3046static bool SearchStringMultiple(Handle<String> subject,
3047 Handle<String> pattern,
3048 Handle<JSArray> last_match_info,
3049 FixedArrayBuilder* builder) {
3050 ASSERT(subject->IsFlat());
3051 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003052
3053 // Treating as if a previous match was before first character.
3054 int match_pos = -pattern->length();
3055
3056 for (;;) { // Break when search complete.
3057 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3058 AssertNoAllocation no_gc;
3059 if (subject->IsAsciiRepresentation()) {
3060 Vector<const char> subject_vector = subject->ToAsciiVector();
3061 if (pattern->IsAsciiRepresentation()) {
3062 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003063 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003064 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003065 builder,
3066 &match_pos)) break;
3067 } else {
3068 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003069 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003070 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003071 builder,
3072 &match_pos)) break;
3073 }
3074 } else {
3075 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3076 if (pattern->IsAsciiRepresentation()) {
3077 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003078 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003079 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003080 builder,
3081 &match_pos)) break;
3082 } else {
3083 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003084 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003085 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003086 builder,
3087 &match_pos)) break;
3088 }
3089 }
3090 }
3091
3092 if (match_pos >= 0) {
3093 SetLastMatchInfoNoCaptures(subject,
3094 last_match_info,
3095 match_pos,
3096 match_pos + pattern->length());
3097 return true;
3098 }
3099 return false; // No matches at all.
3100}
3101
3102
3103static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3104 Handle<String> subject,
3105 Handle<JSRegExp> regexp,
3106 Handle<JSArray> last_match_array,
3107 FixedArrayBuilder* builder) {
3108 ASSERT(subject->IsFlat());
3109 int match_start = -1;
3110 int match_end = 0;
3111 int pos = 0;
3112 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3113 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3114
3115 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003116 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003117 int subject_length = subject->length();
3118
3119 for (;;) { // Break on failure, return on exception.
3120 RegExpImpl::IrregexpResult result =
3121 RegExpImpl::IrregexpExecOnce(regexp,
3122 subject,
3123 pos,
3124 register_vector);
3125 if (result == RegExpImpl::RE_SUCCESS) {
3126 match_start = register_vector[0];
3127 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3128 if (match_end < match_start) {
3129 ReplacementStringBuilder::AddSubjectSlice(builder,
3130 match_end,
3131 match_start);
3132 }
3133 match_end = register_vector[1];
3134 HandleScope loop_scope;
3135 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3136 if (match_start != match_end) {
3137 pos = match_end;
3138 } else {
3139 pos = match_end + 1;
3140 if (pos > subject_length) break;
3141 }
3142 } else if (result == RegExpImpl::RE_FAILURE) {
3143 break;
3144 } else {
3145 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3146 return result;
3147 }
3148 }
3149
3150 if (match_start >= 0) {
3151 if (match_end < subject_length) {
3152 ReplacementStringBuilder::AddSubjectSlice(builder,
3153 match_end,
3154 subject_length);
3155 }
3156 SetLastMatchInfoNoCaptures(subject,
3157 last_match_array,
3158 match_start,
3159 match_end);
3160 return RegExpImpl::RE_SUCCESS;
3161 } else {
3162 return RegExpImpl::RE_FAILURE; // No matches at all.
3163 }
3164}
3165
3166
3167static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3168 Handle<String> subject,
3169 Handle<JSRegExp> regexp,
3170 Handle<JSArray> last_match_array,
3171 FixedArrayBuilder* builder) {
3172
3173 ASSERT(subject->IsFlat());
3174 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3175 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3176
3177 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003178 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003179
3180 RegExpImpl::IrregexpResult result =
3181 RegExpImpl::IrregexpExecOnce(regexp,
3182 subject,
3183 0,
3184 register_vector);
3185
3186 int capture_count = regexp->CaptureCount();
3187 int subject_length = subject->length();
3188
3189 // Position to search from.
3190 int pos = 0;
3191 // End of previous match. Differs from pos if match was empty.
3192 int match_end = 0;
3193 if (result == RegExpImpl::RE_SUCCESS) {
3194 // Need to keep a copy of the previous match for creating last_match_info
3195 // at the end, so we have two vectors that we swap between.
3196 OffsetsVector registers2(required_registers);
3197 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3198
3199 do {
3200 int match_start = register_vector[0];
3201 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3202 if (match_end < match_start) {
3203 ReplacementStringBuilder::AddSubjectSlice(builder,
3204 match_end,
3205 match_start);
3206 }
3207 match_end = register_vector[1];
3208
3209 {
3210 // Avoid accumulating new handles inside loop.
3211 HandleScope temp_scope;
3212 // Arguments array to replace function is match, captures, index and
3213 // subject, i.e., 3 + capture count in total.
3214 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003215 Handle<String> match = Factory::NewSubString(subject,
3216 match_start,
3217 match_end);
3218 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003219 for (int i = 1; i <= capture_count; i++) {
3220 int start = register_vector[i * 2];
3221 if (start >= 0) {
3222 int end = register_vector[i * 2 + 1];
3223 ASSERT(start <= end);
3224 Handle<String> substring = Factory::NewSubString(subject,
3225 start,
3226 end);
3227 elements->set(i, *substring);
3228 } else {
3229 ASSERT(register_vector[i * 2 + 1] < 0);
3230 elements->set(i, Heap::undefined_value());
3231 }
3232 }
3233 elements->set(capture_count + 1, Smi::FromInt(match_start));
3234 elements->set(capture_count + 2, *subject);
3235 builder->Add(*Factory::NewJSArrayWithElements(elements));
3236 }
3237 // Swap register vectors, so the last successful match is in
3238 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003239 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003240 prev_register_vector = register_vector;
3241 register_vector = tmp;
3242
3243 if (match_end > match_start) {
3244 pos = match_end;
3245 } else {
3246 pos = match_end + 1;
3247 if (pos > subject_length) {
3248 break;
3249 }
3250 }
3251
3252 result = RegExpImpl::IrregexpExecOnce(regexp,
3253 subject,
3254 pos,
3255 register_vector);
3256 } while (result == RegExpImpl::RE_SUCCESS);
3257
3258 if (result != RegExpImpl::RE_EXCEPTION) {
3259 // Finished matching, with at least one match.
3260 if (match_end < subject_length) {
3261 ReplacementStringBuilder::AddSubjectSlice(builder,
3262 match_end,
3263 subject_length);
3264 }
3265
3266 int last_match_capture_count = (capture_count + 1) * 2;
3267 int last_match_array_size =
3268 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3269 last_match_array->EnsureSize(last_match_array_size);
3270 AssertNoAllocation no_gc;
3271 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3272 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3273 RegExpImpl::SetLastSubject(elements, *subject);
3274 RegExpImpl::SetLastInput(elements, *subject);
3275 for (int i = 0; i < last_match_capture_count; i++) {
3276 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3277 }
3278 return RegExpImpl::RE_SUCCESS;
3279 }
3280 }
3281 // No matches at all, return failure or exception result directly.
3282 return result;
3283}
3284
3285
lrn@chromium.org303ada72010-10-27 09:33:13 +00003286static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003287 ASSERT(args.length() == 4);
3288 HandleScope handles;
3289
3290 CONVERT_ARG_CHECKED(String, subject, 1);
3291 if (!subject->IsFlat()) { FlattenString(subject); }
3292 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3293 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3294 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3295
3296 ASSERT(last_match_info->HasFastElements());
3297 ASSERT(regexp->GetFlags().is_global());
3298 Handle<FixedArray> result_elements;
3299 if (result_array->HasFastElements()) {
3300 result_elements =
3301 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3302 } else {
3303 result_elements = Factory::NewFixedArrayWithHoles(16);
3304 }
3305 FixedArrayBuilder builder(result_elements);
3306
3307 if (regexp->TypeTag() == JSRegExp::ATOM) {
3308 Handle<String> pattern(
3309 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003310 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003311 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3312 return *builder.ToJSArray(result_array);
3313 }
3314 return Heap::null_value();
3315 }
3316
3317 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3318
3319 RegExpImpl::IrregexpResult result;
3320 if (regexp->CaptureCount() == 0) {
3321 result = SearchRegExpNoCaptureMultiple(subject,
3322 regexp,
3323 last_match_info,
3324 &builder);
3325 } else {
3326 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3327 }
3328 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3329 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3330 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3331 return Failure::Exception();
3332}
3333
3334
lrn@chromium.org303ada72010-10-27 09:33:13 +00003335static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003336 NoHandleAllocation ha;
3337 ASSERT(args.length() == 2);
3338
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003339 // Fast case where the result is a one character string.
3340 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3341 int value = Smi::cast(args[0])->value();
3342 int radix = Smi::cast(args[1])->value();
3343 if (value >= 0 && value < radix) {
3344 RUNTIME_ASSERT(radix <= 36);
3345 // Character array used for conversion.
3346 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3347 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3348 }
3349 }
3350
3351 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003352 CONVERT_DOUBLE_CHECKED(value, args[0]);
3353 if (isnan(value)) {
3354 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3355 }
3356 if (isinf(value)) {
3357 if (value < 0) {
3358 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3359 }
3360 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3361 }
3362 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3363 int radix = FastD2I(radix_number);
3364 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3365 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003366 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003367 DeleteArray(str);
3368 return result;
3369}
3370
3371
lrn@chromium.org303ada72010-10-27 09:33:13 +00003372static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003373 NoHandleAllocation ha;
3374 ASSERT(args.length() == 2);
3375
3376 CONVERT_DOUBLE_CHECKED(value, args[0]);
3377 if (isnan(value)) {
3378 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3379 }
3380 if (isinf(value)) {
3381 if (value < 0) {
3382 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3383 }
3384 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3385 }
3386 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3387 int f = FastD2I(f_number);
3388 RUNTIME_ASSERT(f >= 0);
3389 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003390 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003391 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003392 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003393}
3394
3395
lrn@chromium.org303ada72010-10-27 09:33:13 +00003396static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003397 NoHandleAllocation ha;
3398 ASSERT(args.length() == 2);
3399
3400 CONVERT_DOUBLE_CHECKED(value, args[0]);
3401 if (isnan(value)) {
3402 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3403 }
3404 if (isinf(value)) {
3405 if (value < 0) {
3406 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3407 }
3408 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3409 }
3410 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3411 int f = FastD2I(f_number);
3412 RUNTIME_ASSERT(f >= -1 && f <= 20);
3413 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003414 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003415 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003416 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003417}
3418
3419
lrn@chromium.org303ada72010-10-27 09:33:13 +00003420static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003421 NoHandleAllocation ha;
3422 ASSERT(args.length() == 2);
3423
3424 CONVERT_DOUBLE_CHECKED(value, args[0]);
3425 if (isnan(value)) {
3426 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3427 }
3428 if (isinf(value)) {
3429 if (value < 0) {
3430 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3431 }
3432 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3433 }
3434 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3435 int f = FastD2I(f_number);
3436 RUNTIME_ASSERT(f >= 1 && f <= 21);
3437 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003438 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003439 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003440 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003441}
3442
3443
3444// Returns a single character string where first character equals
3445// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003446static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003447 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003448 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003449 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003450 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003451 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003452 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003453}
3454
3455
lrn@chromium.org303ada72010-10-27 09:33:13 +00003456MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3457 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003458 // Handle [] indexing on Strings
3459 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003460 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3461 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003462 }
3463
3464 // Handle [] indexing on String objects
3465 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003466 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3467 Handle<Object> result =
3468 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3469 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003470 }
3471
3472 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003473 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003474 return prototype->GetElement(index);
3475 }
3476
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003477 return GetElement(object, index);
3478}
3479
3480
lrn@chromium.org303ada72010-10-27 09:33:13 +00003481MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003482 return object->GetElement(index);
3483}
3484
3485
lrn@chromium.org303ada72010-10-27 09:33:13 +00003486MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3487 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003488 HandleScope scope;
3489
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003490 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003491 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003492 Handle<Object> error =
3493 Factory::NewTypeError("non_object_property_load",
3494 HandleVector(args, 2));
3495 return Top::Throw(*error);
3496 }
3497
3498 // Check if the given key is an array index.
3499 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003500 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003501 return GetElementOrCharAt(object, index);
3502 }
3503
3504 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003505 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003506 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003507 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003508 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003509 bool has_pending_exception = false;
3510 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003511 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003512 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003513 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003514 }
3515
ager@chromium.org32912102009-01-16 10:38:43 +00003516 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003517 // the element if so.
3518 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003519 return GetElementOrCharAt(object, index);
3520 } else {
3521 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003522 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003523 }
3524}
3525
3526
lrn@chromium.org303ada72010-10-27 09:33:13 +00003527static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003528 NoHandleAllocation ha;
3529 ASSERT(args.length() == 2);
3530
3531 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003532 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003533
3534 return Runtime::GetObjectProperty(object, key);
3535}
3536
3537
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003538// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003539static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003540 NoHandleAllocation ha;
3541 ASSERT(args.length() == 2);
3542
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003543 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003544 // itself.
3545 //
3546 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003547 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003548 // global proxy object never has properties. This is the case
3549 // because the global proxy object forwards everything to its hidden
3550 // prototype including local lookups.
3551 //
3552 // Additionally, we need to make sure that we do not cache results
3553 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003554 if (args[0]->IsJSObject() &&
3555 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003556 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003557 args[1]->IsString()) {
3558 JSObject* receiver = JSObject::cast(args[0]);
3559 String* key = String::cast(args[1]);
3560 if (receiver->HasFastProperties()) {
3561 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003562 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003563 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3564 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003565 Object* value = receiver->FastPropertyAt(offset);
3566 return value->IsTheHole() ? Heap::undefined_value() : value;
3567 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003568 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003569 LookupResult result;
3570 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003571 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003572 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003573 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003574 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003575 }
3576 } else {
3577 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003578 StringDictionary* dictionary = receiver->property_dictionary();
3579 int entry = dictionary->FindEntry(key);
3580 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003581 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003582 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003583 if (!receiver->IsGlobalObject()) return value;
3584 value = JSGlobalPropertyCell::cast(value)->value();
3585 if (!value->IsTheHole()) return value;
3586 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003587 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003588 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003589 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3590 // Fast case for string indexing using [] with a smi index.
3591 HandleScope scope;
3592 Handle<String> str = args.at<String>(0);
3593 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003594 if (index >= 0 && index < str->length()) {
3595 Handle<Object> result = GetCharAt(str, index);
3596 return *result;
3597 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003598 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003599
3600 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003601 return Runtime::GetObjectProperty(args.at<Object>(0),
3602 args.at<Object>(1));
3603}
3604
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003605// Implements part of 8.12.9 DefineOwnProperty.
3606// There are 3 cases that lead here:
3607// Step 4b - define a new accessor property.
3608// Steps 9c & 12 - replace an existing data property with an accessor property.
3609// Step 12 - update an existing accessor property with an accessor or generic
3610// descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003611static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003612 ASSERT(args.length() == 5);
3613 HandleScope scope;
3614 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3615 CONVERT_CHECKED(String, name, args[1]);
3616 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003617 Object* fun = args[3];
3618 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003619 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3620 int unchecked = flag_attr->value();
3621 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3622 RUNTIME_ASSERT(!obj->IsNull());
3623 LookupResult result;
3624 obj->LocalLookupRealNamedProperty(name, &result);
3625
3626 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3627 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3628 // delete it to avoid running into trouble in DefineAccessor, which
3629 // handles this incorrectly if the property is readonly (does nothing)
3630 if (result.IsProperty() &&
3631 (result.type() == FIELD || result.type() == NORMAL
3632 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003633 Object* ok;
3634 { MaybeObject* maybe_ok =
3635 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3636 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3637 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003638 }
3639 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3640}
3641
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003642// Implements part of 8.12.9 DefineOwnProperty.
3643// There are 3 cases that lead here:
3644// Step 4a - define a new data property.
3645// Steps 9b & 12 - replace an existing accessor property with a data property.
3646// Step 12 - update an existing data property with a data or generic
3647// descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003648static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003649 ASSERT(args.length() == 4);
3650 HandleScope scope;
3651 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3652 CONVERT_ARG_CHECKED(String, name, 1);
3653 Handle<Object> obj_value = args.at<Object>(2);
3654
3655 CONVERT_CHECKED(Smi, flag, args[3]);
3656 int unchecked = flag->value();
3657 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3658
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003659 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3660
3661 // Check if this is an element.
3662 uint32_t index;
3663 bool is_element = name->AsArrayIndex(&index);
3664
3665 // Special case for elements if any of the flags are true.
3666 // If elements are in fast case we always implicitly assume that:
3667 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3668 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3669 is_element) {
3670 // Normalize the elements to enable attributes on the property.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003671 if (!js_object->IsJSGlobalProxy()) {
3672 NormalizeElements(js_object);
3673 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00003674 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003675 // Make sure that we never go back to fast case.
3676 dictionary->set_requires_slow_elements();
3677 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003678 NumberDictionarySet(dictionary, index, obj_value, details);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003679 }
3680
ager@chromium.org5c838252010-02-19 08:53:10 +00003681 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003682 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003683
ager@chromium.org5c838252010-02-19 08:53:10 +00003684 // Take special care when attributes are different and there is already
3685 // a property. For simplicity we normalize the property which enables us
3686 // to not worry about changing the instance_descriptor and creating a new
3687 // map. The current version of SetObjectProperty does not handle attributes
3688 // correctly in the case where a property is a field and is reset with
3689 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003690 if (result.IsProperty() &&
3691 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003692 // New attributes - normalize to avoid writing to instance descriptor
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003693 if (!js_object->IsJSGlobalProxy()) {
3694 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
3695 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003696 // Use IgnoreAttributes version since a readonly property may be
3697 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003698 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3699 *obj_value,
3700 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003701 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003702
ager@chromium.org5c838252010-02-19 08:53:10 +00003703 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3704}
3705
3706
lrn@chromium.org303ada72010-10-27 09:33:13 +00003707MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3708 Handle<Object> key,
3709 Handle<Object> value,
3710 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003711 HandleScope scope;
3712
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003713 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003714 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715 Handle<Object> error =
3716 Factory::NewTypeError("non_object_property_store",
3717 HandleVector(args, 2));
3718 return Top::Throw(*error);
3719 }
3720
3721 // If the object isn't a JavaScript object, we ignore the store.
3722 if (!object->IsJSObject()) return *value;
3723
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003724 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3725
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003726 // Check if the given key is an array index.
3727 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003728 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003729 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3730 // of a string using [] notation. We need to support this too in
3731 // JavaScript.
3732 // In the case of a String object we just need to redirect the assignment to
3733 // the underlying string if the index is in range. Since the underlying
3734 // string does nothing with the assignment then we can ignore such
3735 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003736 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003737 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003738 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003739
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003740 Handle<Object> result = SetElement(js_object, index, value);
3741 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003742 return *value;
3743 }
3744
3745 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003746 Handle<Object> result;
3747 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003748 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003749 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003750 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003751 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003752 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003753 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003754 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003755 return *value;
3756 }
3757
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003758 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003759 bool has_pending_exception = false;
3760 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3761 if (has_pending_exception) return Failure::Exception();
3762 Handle<String> name = Handle<String>::cast(converted);
3763
3764 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003765 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003766 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003767 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003768 }
3769}
3770
3771
lrn@chromium.org303ada72010-10-27 09:33:13 +00003772MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3773 Handle<Object> key,
3774 Handle<Object> value,
3775 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003776 HandleScope scope;
3777
3778 // Check if the given key is an array index.
3779 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003780 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003781 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3782 // of a string using [] notation. We need to support this too in
3783 // JavaScript.
3784 // In the case of a String object we just need to redirect the assignment to
3785 // the underlying string if the index is in range. Since the underlying
3786 // string does nothing with the assignment then we can ignore such
3787 // assignments.
3788 if (js_object->IsStringObjectWithCharacterAt(index)) {
3789 return *value;
3790 }
3791
3792 return js_object->SetElement(index, *value);
3793 }
3794
3795 if (key->IsString()) {
3796 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003797 return js_object->SetElement(index, *value);
3798 } else {
3799 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003800 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003801 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
3802 *value,
3803 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003804 }
3805 }
3806
3807 // Call-back into JavaScript to convert the key to a string.
3808 bool has_pending_exception = false;
3809 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3810 if (has_pending_exception) return Failure::Exception();
3811 Handle<String> name = Handle<String>::cast(converted);
3812
3813 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003814 return js_object->SetElement(index, *value);
3815 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003816 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003817 }
3818}
3819
3820
lrn@chromium.org303ada72010-10-27 09:33:13 +00003821MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3822 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003823 HandleScope scope;
3824
3825 // Check if the given key is an array index.
3826 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003827 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003828 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3829 // characters of a string using [] notation. In the case of a
3830 // String object we just need to redirect the deletion to the
3831 // underlying string if the index is in range. Since the
3832 // underlying string does nothing with the deletion, we can ignore
3833 // such deletions.
3834 if (js_object->IsStringObjectWithCharacterAt(index)) {
3835 return Heap::true_value();
3836 }
3837
3838 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3839 }
3840
3841 Handle<String> key_string;
3842 if (key->IsString()) {
3843 key_string = Handle<String>::cast(key);
3844 } else {
3845 // Call-back into JavaScript to convert the key to a string.
3846 bool has_pending_exception = false;
3847 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3848 if (has_pending_exception) return Failure::Exception();
3849 key_string = Handle<String>::cast(converted);
3850 }
3851
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003852 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003853 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3854}
3855
3856
lrn@chromium.org303ada72010-10-27 09:33:13 +00003857static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003858 NoHandleAllocation ha;
3859 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3860
3861 Handle<Object> object = args.at<Object>(0);
3862 Handle<Object> key = args.at<Object>(1);
3863 Handle<Object> value = args.at<Object>(2);
3864
3865 // Compute attributes.
3866 PropertyAttributes attributes = NONE;
3867 if (args.length() == 4) {
3868 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003869 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003870 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003871 RUNTIME_ASSERT(
3872 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3873 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003874 }
3875 return Runtime::SetObjectProperty(object, key, value, attributes);
3876}
3877
3878
3879// Set a local property, even if it is READ_ONLY. If the property does not
3880// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003881static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003882 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003883 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003884 CONVERT_CHECKED(JSObject, object, args[0]);
3885 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003886 // Compute attributes.
3887 PropertyAttributes attributes = NONE;
3888 if (args.length() == 4) {
3889 CONVERT_CHECKED(Smi, value_obj, args[3]);
3890 int unchecked_value = value_obj->value();
3891 // Only attribute bits should be set.
3892 RUNTIME_ASSERT(
3893 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3894 attributes = static_cast<PropertyAttributes>(unchecked_value);
3895 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003896
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003897 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003898 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003899}
3900
3901
lrn@chromium.org303ada72010-10-27 09:33:13 +00003902static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003903 NoHandleAllocation ha;
3904 ASSERT(args.length() == 2);
3905
3906 CONVERT_CHECKED(JSObject, object, args[0]);
3907 CONVERT_CHECKED(String, key, args[1]);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003908 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003909}
3910
3911
ager@chromium.org9085a012009-05-11 19:22:57 +00003912static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3913 Handle<String> key) {
3914 if (object->HasLocalProperty(*key)) return Heap::true_value();
3915 // Handle hidden prototypes. If there's a hidden prototype above this thing
3916 // then we have to check it for properties, because they are supposed to
3917 // look like they are on this object.
3918 Handle<Object> proto(object->GetPrototype());
3919 if (proto->IsJSObject() &&
3920 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3921 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3922 }
3923 return Heap::false_value();
3924}
3925
3926
lrn@chromium.org303ada72010-10-27 09:33:13 +00003927static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003928 NoHandleAllocation ha;
3929 ASSERT(args.length() == 2);
3930 CONVERT_CHECKED(String, key, args[1]);
3931
ager@chromium.org9085a012009-05-11 19:22:57 +00003932 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003933 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003934 if (obj->IsJSObject()) {
3935 JSObject* object = JSObject::cast(obj);
3936 // Fast case - no interceptors.
3937 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3938 // Slow case. Either it's not there or we have an interceptor. We should
3939 // have handles for this kind of deal.
3940 HandleScope scope;
3941 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3942 Handle<String>(key));
3943 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003944 // Well, there is one exception: Handle [] on strings.
3945 uint32_t index;
3946 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003947 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003948 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003949 return Heap::true_value();
3950 }
3951 }
3952 return Heap::false_value();
3953}
3954
3955
lrn@chromium.org303ada72010-10-27 09:33:13 +00003956static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003957 NoHandleAllocation na;
3958 ASSERT(args.length() == 2);
3959
3960 // Only JS objects can have properties.
3961 if (args[0]->IsJSObject()) {
3962 JSObject* object = JSObject::cast(args[0]);
3963 CONVERT_CHECKED(String, key, args[1]);
3964 if (object->HasProperty(key)) return Heap::true_value();
3965 }
3966 return Heap::false_value();
3967}
3968
3969
lrn@chromium.org303ada72010-10-27 09:33:13 +00003970static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003971 NoHandleAllocation na;
3972 ASSERT(args.length() == 2);
3973
3974 // Only JS objects can have elements.
3975 if (args[0]->IsJSObject()) {
3976 JSObject* object = JSObject::cast(args[0]);
3977 CONVERT_CHECKED(Smi, index_obj, args[1]);
3978 uint32_t index = index_obj->value();
3979 if (object->HasElement(index)) return Heap::true_value();
3980 }
3981 return Heap::false_value();
3982}
3983
3984
lrn@chromium.org303ada72010-10-27 09:33:13 +00003985static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003986 NoHandleAllocation ha;
3987 ASSERT(args.length() == 2);
3988
3989 CONVERT_CHECKED(JSObject, object, args[0]);
3990 CONVERT_CHECKED(String, key, args[1]);
3991
3992 uint32_t index;
3993 if (key->AsArrayIndex(&index)) {
3994 return Heap::ToBoolean(object->HasElement(index));
3995 }
3996
ager@chromium.org870a0b62008-11-04 11:43:05 +00003997 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
3998 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003999}
4000
4001
lrn@chromium.org303ada72010-10-27 09:33:13 +00004002static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004003 HandleScope scope;
4004 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004005 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004006 return *GetKeysFor(object);
4007}
4008
4009
4010// Returns either a FixedArray as Runtime_GetPropertyNames,
4011// or, if the given object has an enum cache that contains
4012// all enumerable properties of the object and its prototypes
4013// have none, the map of the object. This is used to speed up
4014// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004015static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004016 ASSERT(args.length() == 1);
4017
4018 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4019
4020 if (raw_object->IsSimpleEnum()) return raw_object->map();
4021
4022 HandleScope scope;
4023 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004024 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4025 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004026
4027 // Test again, since cache may have been built by preceding call.
4028 if (object->IsSimpleEnum()) return object->map();
4029
4030 return *content;
4031}
4032
4033
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004034// Find the length of the prototype chain that is to to handled as one. If a
4035// prototype object is hidden it is to be viewed as part of the the object it
4036// is prototype for.
4037static int LocalPrototypeChainLength(JSObject* obj) {
4038 int count = 1;
4039 Object* proto = obj->GetPrototype();
4040 while (proto->IsJSObject() &&
4041 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4042 count++;
4043 proto = JSObject::cast(proto)->GetPrototype();
4044 }
4045 return count;
4046}
4047
4048
4049// Return the names of the local named properties.
4050// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004051static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004052 HandleScope scope;
4053 ASSERT(args.length() == 1);
4054 if (!args[0]->IsJSObject()) {
4055 return Heap::undefined_value();
4056 }
4057 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4058
4059 // Skip the global proxy as it has no properties and always delegates to the
4060 // real global object.
4061 if (obj->IsJSGlobalProxy()) {
4062 // Only collect names if access is permitted.
4063 if (obj->IsAccessCheckNeeded() &&
4064 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
4065 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4066 return *Factory::NewJSArray(0);
4067 }
4068 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4069 }
4070
4071 // Find the number of objects making up this.
4072 int length = LocalPrototypeChainLength(*obj);
4073
4074 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004075 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004076 int total_property_count = 0;
4077 Handle<JSObject> jsproto = obj;
4078 for (int i = 0; i < length; i++) {
4079 // Only collect names if access is permitted.
4080 if (jsproto->IsAccessCheckNeeded() &&
4081 !Top::MayNamedAccess(*jsproto,
4082 Heap::undefined_value(),
4083 v8::ACCESS_KEYS)) {
4084 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4085 return *Factory::NewJSArray(0);
4086 }
4087 int n;
4088 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4089 local_property_count[i] = n;
4090 total_property_count += n;
4091 if (i < length - 1) {
4092 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4093 }
4094 }
4095
4096 // Allocate an array with storage for all the property names.
4097 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
4098
4099 // Get the property names.
4100 jsproto = obj;
4101 int proto_with_hidden_properties = 0;
4102 for (int i = 0; i < length; i++) {
4103 jsproto->GetLocalPropertyNames(*names,
4104 i == 0 ? 0 : local_property_count[i - 1]);
4105 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4106 proto_with_hidden_properties++;
4107 }
4108 if (i < length - 1) {
4109 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4110 }
4111 }
4112
4113 // Filter out name of hidden propeties object.
4114 if (proto_with_hidden_properties > 0) {
4115 Handle<FixedArray> old_names = names;
4116 names = Factory::NewFixedArray(
4117 names->length() - proto_with_hidden_properties);
4118 int dest_pos = 0;
4119 for (int i = 0; i < total_property_count; i++) {
4120 Object* name = old_names->get(i);
4121 if (name == Heap::hidden_symbol()) {
4122 continue;
4123 }
4124 names->set(dest_pos++, name);
4125 }
4126 }
4127
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004128 return *Factory::NewJSArrayWithElements(names);
4129}
4130
4131
4132// Return the names of the local indexed properties.
4133// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004134static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004135 HandleScope scope;
4136 ASSERT(args.length() == 1);
4137 if (!args[0]->IsJSObject()) {
4138 return Heap::undefined_value();
4139 }
4140 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4141
4142 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4143 Handle<FixedArray> names = Factory::NewFixedArray(n);
4144 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4145 return *Factory::NewJSArrayWithElements(names);
4146}
4147
4148
4149// Return information on whether an object has a named or indexed interceptor.
4150// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004151static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004152 HandleScope scope;
4153 ASSERT(args.length() == 1);
4154 if (!args[0]->IsJSObject()) {
4155 return Smi::FromInt(0);
4156 }
4157 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4158
4159 int result = 0;
4160 if (obj->HasNamedInterceptor()) result |= 2;
4161 if (obj->HasIndexedInterceptor()) result |= 1;
4162
4163 return Smi::FromInt(result);
4164}
4165
4166
4167// Return property names from named interceptor.
4168// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004169static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004170 HandleScope scope;
4171 ASSERT(args.length() == 1);
4172 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4173
4174 if (obj->HasNamedInterceptor()) {
4175 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4176 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4177 }
4178 return Heap::undefined_value();
4179}
4180
4181
4182// Return element names from indexed interceptor.
4183// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004184static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004185 HandleScope scope;
4186 ASSERT(args.length() == 1);
4187 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4188
4189 if (obj->HasIndexedInterceptor()) {
4190 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4191 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4192 }
4193 return Heap::undefined_value();
4194}
4195
4196
lrn@chromium.org303ada72010-10-27 09:33:13 +00004197static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004198 ASSERT_EQ(args.length(), 1);
4199 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4200 HandleScope scope;
4201 Handle<JSObject> object(raw_object);
4202 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4203 LOCAL_ONLY);
4204 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4205 // property array and since the result is mutable we have to create
4206 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004207 int length = contents->length();
4208 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4209 for (int i = 0; i < length; i++) {
4210 Object* entry = contents->get(i);
4211 if (entry->IsString()) {
4212 copy->set(i, entry);
4213 } else {
4214 ASSERT(entry->IsNumber());
4215 HandleScope scope;
4216 Handle<Object> entry_handle(entry);
4217 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4218 copy->set(i, *entry_str);
4219 }
4220 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004221 return *Factory::NewJSArrayWithElements(copy);
4222}
4223
4224
lrn@chromium.org303ada72010-10-27 09:33:13 +00004225static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004226 NoHandleAllocation ha;
4227 ASSERT(args.length() == 1);
4228
4229 // Compute the frame holding the arguments.
4230 JavaScriptFrameIterator it;
4231 it.AdvanceToArgumentsFrame();
4232 JavaScriptFrame* frame = it.frame();
4233
4234 // Get the actual number of provided arguments.
4235 const uint32_t n = frame->GetProvidedParametersCount();
4236
4237 // Try to convert the key to an index. If successful and within
4238 // index return the the argument from the frame.
4239 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004240 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004241 return frame->GetParameter(index);
4242 }
4243
4244 // Convert the key to a string.
4245 HandleScope scope;
4246 bool exception = false;
4247 Handle<Object> converted =
4248 Execution::ToString(args.at<Object>(0), &exception);
4249 if (exception) return Failure::Exception();
4250 Handle<String> key = Handle<String>::cast(converted);
4251
4252 // Try to convert the string key into an array index.
4253 if (key->AsArrayIndex(&index)) {
4254 if (index < n) {
4255 return frame->GetParameter(index);
4256 } else {
4257 return Top::initial_object_prototype()->GetElement(index);
4258 }
4259 }
4260
4261 // Handle special arguments properties.
4262 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4263 if (key->Equals(Heap::callee_symbol())) return frame->function();
4264
4265 // Lookup in the initial Object.prototype object.
4266 return Top::initial_object_prototype()->GetProperty(*key);
4267}
4268
4269
lrn@chromium.org303ada72010-10-27 09:33:13 +00004270static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004271 HandleScope scope;
4272
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004273 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004274 Handle<Object> object = args.at<Object>(0);
4275 if (object->IsJSObject()) {
4276 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004277 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004278 MaybeObject* ok = js_object->TransformToFastProperties(0);
4279 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004280 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004281 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004282 return *object;
4283}
4284
4285
lrn@chromium.org303ada72010-10-27 09:33:13 +00004286static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004287 HandleScope scope;
4288
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004289 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004290 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004291 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004292 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004293 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004294 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004295 return *object;
4296}
4297
4298
lrn@chromium.org303ada72010-10-27 09:33:13 +00004299static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004300 NoHandleAllocation ha;
4301 ASSERT(args.length() == 1);
4302
4303 return args[0]->ToBoolean();
4304}
4305
4306
4307// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4308// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004309static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004310 NoHandleAllocation ha;
4311
4312 Object* obj = args[0];
4313 if (obj->IsNumber()) return Heap::number_symbol();
4314 HeapObject* heap_obj = HeapObject::cast(obj);
4315
4316 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004317 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004318
4319 InstanceType instance_type = heap_obj->map()->instance_type();
4320 if (instance_type < FIRST_NONSTRING_TYPE) {
4321 return Heap::string_symbol();
4322 }
4323
4324 switch (instance_type) {
4325 case ODDBALL_TYPE:
4326 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4327 return Heap::boolean_symbol();
4328 }
4329 if (heap_obj->IsNull()) {
4330 return Heap::object_symbol();
4331 }
4332 ASSERT(heap_obj->IsUndefined());
4333 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004334 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004335 return Heap::function_symbol();
4336 default:
4337 // For any kind of object not handled above, the spec rule for
4338 // host objects gives that it is okay to return "object"
4339 return Heap::object_symbol();
4340 }
4341}
4342
4343
lrn@chromium.org25156de2010-04-06 13:10:27 +00004344static bool AreDigits(const char*s, int from, int to) {
4345 for (int i = from; i < to; i++) {
4346 if (s[i] < '0' || s[i] > '9') return false;
4347 }
4348
4349 return true;
4350}
4351
4352
4353static int ParseDecimalInteger(const char*s, int from, int to) {
4354 ASSERT(to - from < 10); // Overflow is not possible.
4355 ASSERT(from < to);
4356 int d = s[from] - '0';
4357
4358 for (int i = from + 1; i < to; i++) {
4359 d = 10 * d + (s[i] - '0');
4360 }
4361
4362 return d;
4363}
4364
4365
lrn@chromium.org303ada72010-10-27 09:33:13 +00004366static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004367 NoHandleAllocation ha;
4368 ASSERT(args.length() == 1);
4369 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004370 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004371
4372 // Fast case: short integer or some sorts of junk values.
4373 int len = subject->length();
4374 if (subject->IsSeqAsciiString()) {
4375 if (len == 0) return Smi::FromInt(0);
4376
4377 char const* data = SeqAsciiString::cast(subject)->GetChars();
4378 bool minus = (data[0] == '-');
4379 int start_pos = (minus ? 1 : 0);
4380
4381 if (start_pos == len) {
4382 return Heap::nan_value();
4383 } else if (data[start_pos] > '9') {
4384 // Fast check for a junk value. A valid string may start from a
4385 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4386 // the 'I' character ('Infinity'). All of that have codes not greater than
4387 // '9' except 'I'.
4388 if (data[start_pos] != 'I') {
4389 return Heap::nan_value();
4390 }
4391 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4392 // The maximal/minimal smi has 10 digits. If the string has less digits we
4393 // know it will fit into the smi-data type.
4394 int d = ParseDecimalInteger(data, start_pos, len);
4395 if (minus) {
4396 if (d == 0) return Heap::minus_zero_value();
4397 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004398 } else if (!subject->HasHashCode() &&
4399 len <= String::kMaxArrayIndexSize &&
4400 (len == 1 || data[0] != '0')) {
4401 // String hash is not calculated yet but all the data are present.
4402 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004403 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004404#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004405 subject->Hash(); // Force hash calculation.
4406 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4407 static_cast<int>(hash));
4408#endif
4409 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004410 }
4411 return Smi::FromInt(d);
4412 }
4413 }
4414
4415 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004416 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4417}
4418
4419
lrn@chromium.org303ada72010-10-27 09:33:13 +00004420static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004421 NoHandleAllocation ha;
4422 ASSERT(args.length() == 1);
4423
4424 CONVERT_CHECKED(JSArray, codes, args[0]);
4425 int length = Smi::cast(codes->length())->value();
4426
4427 // Check if the string can be ASCII.
4428 int i;
4429 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004430 Object* element;
4431 { MaybeObject* maybe_element = codes->GetElement(i);
4432 // We probably can't get an exception here, but just in order to enforce
4433 // the checking of inputs in the runtime calls we check here.
4434 if (!maybe_element->ToObject(&element)) return maybe_element;
4435 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004436 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4437 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4438 break;
4439 }
4440
lrn@chromium.org303ada72010-10-27 09:33:13 +00004441 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004442 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004443 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004444 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004445 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004446 }
4447
lrn@chromium.org303ada72010-10-27 09:33:13 +00004448 Object* object = NULL;
4449 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004450 String* result = String::cast(object);
4451 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004452 Object* element;
4453 { MaybeObject* maybe_element = codes->GetElement(i);
4454 if (!maybe_element->ToObject(&element)) return maybe_element;
4455 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004456 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004457 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004458 }
4459 return result;
4460}
4461
4462
4463// kNotEscaped is generated by the following:
4464//
4465// #!/bin/perl
4466// for (my $i = 0; $i < 256; $i++) {
4467// print "\n" if $i % 16 == 0;
4468// my $c = chr($i);
4469// my $escaped = 1;
4470// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4471// print $escaped ? "0, " : "1, ";
4472// }
4473
4474
4475static bool IsNotEscaped(uint16_t character) {
4476 // Only for 8 bit characters, the rest are always escaped (in a different way)
4477 ASSERT(character < 256);
4478 static const char kNotEscaped[256] = {
4479 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4480 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4481 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4482 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4483 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4484 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4485 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4486 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4487 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4488 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4489 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4490 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4491 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4492 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4493 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4494 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4495 };
4496 return kNotEscaped[character] != 0;
4497}
4498
4499
lrn@chromium.org303ada72010-10-27 09:33:13 +00004500static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004501 const char hex_chars[] = "0123456789ABCDEF";
4502 NoHandleAllocation ha;
4503 ASSERT(args.length() == 1);
4504 CONVERT_CHECKED(String, source, args[0]);
4505
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004506 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004507
4508 int escaped_length = 0;
4509 int length = source->length();
4510 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004511 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004512 buffer->Reset(source);
4513 while (buffer->has_more()) {
4514 uint16_t character = buffer->GetNext();
4515 if (character >= 256) {
4516 escaped_length += 6;
4517 } else if (IsNotEscaped(character)) {
4518 escaped_length++;
4519 } else {
4520 escaped_length += 3;
4521 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004522 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004523 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004524 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004525 Top::context()->mark_out_of_memory();
4526 return Failure::OutOfMemoryException();
4527 }
4528 }
4529 }
4530 // No length change implies no change. Return original string if no change.
4531 if (escaped_length == length) {
4532 return source;
4533 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004534 Object* o;
4535 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4536 if (!maybe_o->ToObject(&o)) return maybe_o;
4537 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004538 String* destination = String::cast(o);
4539 int dest_position = 0;
4540
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004541 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004542 buffer->Rewind();
4543 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004544 uint16_t chr = buffer->GetNext();
4545 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004546 destination->Set(dest_position, '%');
4547 destination->Set(dest_position+1, 'u');
4548 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4549 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4550 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4551 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004552 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004553 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004554 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004555 dest_position++;
4556 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004557 destination->Set(dest_position, '%');
4558 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4559 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004560 dest_position += 3;
4561 }
4562 }
4563 return destination;
4564}
4565
4566
4567static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4568 static const signed char kHexValue['g'] = {
4569 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4570 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4571 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4572 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4573 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4574 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4575 -1, 10, 11, 12, 13, 14, 15 };
4576
4577 if (character1 > 'f') return -1;
4578 int hi = kHexValue[character1];
4579 if (hi == -1) return -1;
4580 if (character2 > 'f') return -1;
4581 int lo = kHexValue[character2];
4582 if (lo == -1) return -1;
4583 return (hi << 4) + lo;
4584}
4585
4586
ager@chromium.org870a0b62008-11-04 11:43:05 +00004587static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004588 int i,
4589 int length,
4590 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004591 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004592 int32_t hi = 0;
4593 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004594 if (character == '%' &&
4595 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004596 source->Get(i + 1) == 'u' &&
4597 (hi = TwoDigitHex(source->Get(i + 2),
4598 source->Get(i + 3))) != -1 &&
4599 (lo = TwoDigitHex(source->Get(i + 4),
4600 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004601 *step = 6;
4602 return (hi << 8) + lo;
4603 } else if (character == '%' &&
4604 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004605 (lo = TwoDigitHex(source->Get(i + 1),
4606 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004607 *step = 3;
4608 return lo;
4609 } else {
4610 *step = 1;
4611 return character;
4612 }
4613}
4614
4615
lrn@chromium.org303ada72010-10-27 09:33:13 +00004616static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004617 NoHandleAllocation ha;
4618 ASSERT(args.length() == 1);
4619 CONVERT_CHECKED(String, source, args[0]);
4620
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004621 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004622
4623 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004624 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004625
4626 int unescaped_length = 0;
4627 for (int i = 0; i < length; unescaped_length++) {
4628 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004629 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004630 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004631 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004632 i += step;
4633 }
4634
4635 // No length change implies no change. Return original string if no change.
4636 if (unescaped_length == length)
4637 return source;
4638
lrn@chromium.org303ada72010-10-27 09:33:13 +00004639 Object* o;
4640 { MaybeObject* maybe_o = ascii ?
4641 Heap::AllocateRawAsciiString(unescaped_length) :
4642 Heap::AllocateRawTwoByteString(unescaped_length);
4643 if (!maybe_o->ToObject(&o)) return maybe_o;
4644 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004645 String* destination = String::cast(o);
4646
4647 int dest_position = 0;
4648 for (int i = 0; i < length; dest_position++) {
4649 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004650 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004651 i += step;
4652 }
4653 return destination;
4654}
4655
4656
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004657static const unsigned int kQuoteTableLength = 128u;
4658
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004659static const int kJsonQuotesCharactersPerEntry = 8;
4660static const char* const JsonQuotes =
4661 "\\u0000 \\u0001 \\u0002 \\u0003 "
4662 "\\u0004 \\u0005 \\u0006 \\u0007 "
4663 "\\b \\t \\n \\u000b "
4664 "\\f \\r \\u000e \\u000f "
4665 "\\u0010 \\u0011 \\u0012 \\u0013 "
4666 "\\u0014 \\u0015 \\u0016 \\u0017 "
4667 "\\u0018 \\u0019 \\u001a \\u001b "
4668 "\\u001c \\u001d \\u001e \\u001f "
4669 " ! \\\" # "
4670 "$ % & ' "
4671 "( ) * + "
4672 ", - . / "
4673 "0 1 2 3 "
4674 "4 5 6 7 "
4675 "8 9 : ; "
4676 "< = > ? "
4677 "@ A B C "
4678 "D E F G "
4679 "H I J K "
4680 "L M N O "
4681 "P Q R S "
4682 "T U V W "
4683 "X Y Z [ "
4684 "\\\\ ] ^ _ "
4685 "` a b c "
4686 "d e f g "
4687 "h i j k "
4688 "l m n o "
4689 "p q r s "
4690 "t u v w "
4691 "x y z { "
4692 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004693
4694
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004695// For a string that is less than 32k characters it should always be
4696// possible to allocate it in new space.
4697static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4698
4699
4700// Doing JSON quoting cannot make the string more than this many times larger.
4701static const int kJsonQuoteWorstCaseBlowup = 6;
4702
4703
4704// Covers the entire ASCII range (all other characters are unchanged by JSON
4705// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004706static const byte JsonQuoteLengths[kQuoteTableLength] = {
4707 6, 6, 6, 6, 6, 6, 6, 6,
4708 2, 2, 2, 6, 2, 2, 6, 6,
4709 6, 6, 6, 6, 6, 6, 6, 6,
4710 6, 6, 6, 6, 6, 6, 6, 6,
4711 1, 1, 2, 1, 1, 1, 1, 1,
4712 1, 1, 1, 1, 1, 1, 1, 1,
4713 1, 1, 1, 1, 1, 1, 1, 1,
4714 1, 1, 1, 1, 1, 1, 1, 1,
4715 1, 1, 1, 1, 1, 1, 1, 1,
4716 1, 1, 1, 1, 1, 1, 1, 1,
4717 1, 1, 1, 1, 1, 1, 1, 1,
4718 1, 1, 1, 1, 2, 1, 1, 1,
4719 1, 1, 1, 1, 1, 1, 1, 1,
4720 1, 1, 1, 1, 1, 1, 1, 1,
4721 1, 1, 1, 1, 1, 1, 1, 1,
4722 1, 1, 1, 1, 1, 1, 1, 1,
4723};
4724
4725
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004726template <typename StringType>
4727MaybeObject* AllocateRawString(int length);
4728
4729
4730template <>
4731MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4732 return Heap::AllocateRawTwoByteString(length);
4733}
4734
4735
4736template <>
4737MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4738 return Heap::AllocateRawAsciiString(length);
4739}
4740
4741
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004742template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004743static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004744 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004745 const Char* read_cursor = characters.start();
4746 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004747 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004748 int quoted_length = kSpaceForQuotes;
4749 while (read_cursor < end) {
4750 Char c = *(read_cursor++);
4751 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4752 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004753 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004754 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004755 }
4756 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004757 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4758 Object* new_object;
4759 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004760 return new_alloc;
4761 }
4762 StringType* new_string = StringType::cast(new_object);
4763
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004764 Char* write_cursor = reinterpret_cast<Char*>(
4765 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004766 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004767 *(write_cursor++) = '"';
4768
4769 read_cursor = characters.start();
4770 while (read_cursor < end) {
4771 Char c = *(read_cursor++);
4772 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4773 *(write_cursor++) = c;
4774 } else {
4775 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4776 const char* replacement = JsonQuotes +
4777 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4778 for (int i = 0; i < len; i++) {
4779 *write_cursor++ = *replacement++;
4780 }
4781 }
4782 }
4783 *(write_cursor++) = '"';
4784 return new_string;
4785}
4786
4787
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004788template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004789static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4790 int length = characters.length();
4791 Counters::quote_json_char_count.Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004792 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004793 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4794 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004795 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004796 }
4797
4798 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4799 Object* new_object;
4800 if (!new_alloc->ToObject(&new_object)) {
4801 return new_alloc;
4802 }
4803 if (!Heap::new_space()->Contains(new_object)) {
4804 // Even if our string is small enough to fit in new space we still have to
4805 // handle it being allocated in old space as may happen in the third
4806 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
4807 // CEntryStub::GenerateCore.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004808 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004809 }
4810 StringType* new_string = StringType::cast(new_object);
4811 ASSERT(Heap::new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004812
4813 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4814 Char* write_cursor = reinterpret_cast<Char*>(
4815 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004816 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004817 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004818
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004819 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004820 const Char* end = read_cursor + length;
4821 while (read_cursor < end) {
4822 Char c = *(read_cursor++);
4823 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4824 *(write_cursor++) = c;
4825 } else {
4826 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4827 const char* replacement = JsonQuotes +
4828 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4829 write_cursor[0] = replacement[0];
4830 if (len > 1) {
4831 write_cursor[1] = replacement[1];
4832 if (len > 2) {
4833 ASSERT(len == 6);
4834 write_cursor[2] = replacement[2];
4835 write_cursor[3] = replacement[3];
4836 write_cursor[4] = replacement[4];
4837 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004838 }
4839 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004840 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004841 }
4842 }
4843 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004844
4845 int final_length = static_cast<int>(
4846 write_cursor - reinterpret_cast<Char*>(
4847 new_string->address() + SeqAsciiString::kHeaderSize));
4848 Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4849 final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004850 return new_string;
4851}
4852
4853
4854static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4855 NoHandleAllocation ha;
4856 CONVERT_CHECKED(String, str, args[0]);
4857 if (!str->IsFlat()) {
4858 MaybeObject* try_flatten = str->TryFlatten();
4859 Object* flat;
4860 if (!try_flatten->ToObject(&flat)) {
4861 return try_flatten;
4862 }
4863 str = String::cast(flat);
4864 ASSERT(str->IsFlat());
4865 }
4866 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004867 return QuoteJsonString<uc16, SeqTwoByteString, false>(str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004868 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004869 return QuoteJsonString<char, SeqAsciiString, false>(str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004870 }
4871}
4872
4873
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004874static MaybeObject* Runtime_QuoteJSONStringComma(Arguments args) {
4875 NoHandleAllocation ha;
4876 CONVERT_CHECKED(String, str, args[0]);
4877 if (!str->IsFlat()) {
4878 MaybeObject* try_flatten = str->TryFlatten();
4879 Object* flat;
4880 if (!try_flatten->ToObject(&flat)) {
4881 return try_flatten;
4882 }
4883 str = String::cast(flat);
4884 ASSERT(str->IsFlat());
4885 }
4886 if (str->IsTwoByteRepresentation()) {
4887 return QuoteJsonString<uc16, SeqTwoByteString, true>(str->ToUC16Vector());
4888 } else {
4889 return QuoteJsonString<char, SeqAsciiString, true>(str->ToAsciiVector());
4890 }
4891}
4892
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004893
lrn@chromium.org303ada72010-10-27 09:33:13 +00004894static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004895 NoHandleAllocation ha;
4896
4897 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004898 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004899
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004900 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004901
lrn@chromium.org25156de2010-04-06 13:10:27 +00004902 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4903 double value = StringToInt(s, radix);
4904 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004905}
4906
4907
lrn@chromium.org303ada72010-10-27 09:33:13 +00004908static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004909 NoHandleAllocation ha;
4910 CONVERT_CHECKED(String, str, args[0]);
4911
4912 // ECMA-262 section 15.1.2.3, empty string is NaN
4913 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4914
4915 // Create a number object from the value.
4916 return Heap::NumberFromDouble(value);
4917}
4918
4919
4920static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4921static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4922
4923
4924template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004925MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
4926 String* s,
4927 int length,
4928 int input_string_length,
4929 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004930 // We try this twice, once with the assumption that the result is no longer
4931 // than the input and, if that assumption breaks, again with the exact
4932 // length. This may not be pretty, but it is nicer than what was here before
4933 // and I hereby claim my vaffel-is.
4934 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004935 // Allocate the resulting string.
4936 //
4937 // NOTE: This assumes that the upper/lower case of an ascii
4938 // character is also ascii. This is currently the case, but it
4939 // might break in the future if we implement more context and locale
4940 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004941 Object* o;
4942 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
4943 ? Heap::AllocateRawAsciiString(length)
4944 : Heap::AllocateRawTwoByteString(length);
4945 if (!maybe_o->ToObject(&o)) return maybe_o;
4946 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004947 String* result = String::cast(o);
4948 bool has_changed_character = false;
4949
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004950 // Convert all characters to upper case, assuming that they will fit
4951 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004952 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004953 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004954 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004955 // We can assume that the string is not empty
4956 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004957 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004958 bool has_next = buffer->has_more();
4959 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004960 int char_length = mapping->get(current, next, chars);
4961 if (char_length == 0) {
4962 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004963 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004964 i++;
4965 } else if (char_length == 1) {
4966 // Common case: converting the letter resulted in one character.
4967 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004968 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004969 has_changed_character = true;
4970 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004971 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004972 // We've assumed that the result would be as long as the
4973 // input but here is a character that converts to several
4974 // characters. No matter, we calculate the exact length
4975 // of the result and try the whole thing again.
4976 //
4977 // Note that this leaves room for optimization. We could just
4978 // memcpy what we already have to the result string. Also,
4979 // the result string is the last object allocated we could
4980 // "realloc" it and probably, in the vast majority of cases,
4981 // extend the existing string to be able to hold the full
4982 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004983 int next_length = 0;
4984 if (has_next) {
4985 next_length = mapping->get(next, 0, chars);
4986 if (next_length == 0) next_length = 1;
4987 }
4988 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004989 while (buffer->has_more()) {
4990 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004991 // NOTE: we use 0 as the next character here because, while
4992 // the next character may affect what a character converts to,
4993 // it does not in any case affect the length of what it convert
4994 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004995 int char_length = mapping->get(current, 0, chars);
4996 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00004997 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004998 if (current_length > Smi::kMaxValue) {
4999 Top::context()->mark_out_of_memory();
5000 return Failure::OutOfMemoryException();
5001 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005002 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005003 // Try again with the real length.
5004 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005005 } else {
5006 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005007 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005008 i++;
5009 }
5010 has_changed_character = true;
5011 }
5012 current = next;
5013 }
5014 if (has_changed_character) {
5015 return result;
5016 } else {
5017 // If we didn't actually change anything in doing the conversion
5018 // we simple return the result and let the converted string
5019 // become garbage; there is no reason to keep two identical strings
5020 // alive.
5021 return s;
5022 }
5023}
5024
5025
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005026namespace {
5027
lrn@chromium.org303ada72010-10-27 09:33:13 +00005028static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5029
5030
5031// Given a word and two range boundaries returns a word with high bit
5032// set in every byte iff the corresponding input byte was strictly in
5033// the range (m, n). All the other bits in the result are cleared.
5034// This function is only useful when it can be inlined and the
5035// boundaries are statically known.
5036// Requires: all bytes in the input word and the boundaries must be
5037// ascii (less than 0x7F).
5038static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5039 // Every byte in an ascii string is less than or equal to 0x7F.
5040 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5041 // Use strict inequalities since in edge cases the function could be
5042 // further simplified.
5043 ASSERT(0 < m && m < n && n < 0x7F);
5044 // Has high bit set in every w byte less than n.
5045 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5046 // Has high bit set in every w byte greater than m.
5047 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5048 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5049}
5050
5051
5052enum AsciiCaseConversion {
5053 ASCII_TO_LOWER,
5054 ASCII_TO_UPPER
5055};
5056
5057
5058template <AsciiCaseConversion dir>
5059struct FastAsciiConverter {
5060 static bool Convert(char* dst, char* src, int length) {
5061#ifdef DEBUG
5062 char* saved_dst = dst;
5063 char* saved_src = src;
5064#endif
5065 // We rely on the distance between upper and lower case letters
5066 // being a known power of 2.
5067 ASSERT('a' - 'A' == (1 << 5));
5068 // Boundaries for the range of input characters than require conversion.
5069 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5070 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5071 bool changed = false;
5072 char* const limit = src + length;
5073#ifdef V8_HOST_CAN_READ_UNALIGNED
5074 // Process the prefix of the input that requires no conversion one
5075 // (machine) word at a time.
5076 while (src <= limit - sizeof(uintptr_t)) {
5077 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5078 if (AsciiRangeMask(w, lo, hi) != 0) {
5079 changed = true;
5080 break;
5081 }
5082 *reinterpret_cast<uintptr_t*>(dst) = w;
5083 src += sizeof(uintptr_t);
5084 dst += sizeof(uintptr_t);
5085 }
5086 // Process the remainder of the input performing conversion when
5087 // required one word at a time.
5088 while (src <= limit - sizeof(uintptr_t)) {
5089 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5090 uintptr_t m = AsciiRangeMask(w, lo, hi);
5091 // The mask has high (7th) bit set in every byte that needs
5092 // conversion and we know that the distance between cases is
5093 // 1 << 5.
5094 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5095 src += sizeof(uintptr_t);
5096 dst += sizeof(uintptr_t);
5097 }
5098#endif
5099 // Process the last few bytes of the input (or the whole input if
5100 // unaligned access is not supported).
5101 while (src < limit) {
5102 char c = *src;
5103 if (lo < c && c < hi) {
5104 c ^= (1 << 5);
5105 changed = true;
5106 }
5107 *dst = c;
5108 ++src;
5109 ++dst;
5110 }
5111#ifdef DEBUG
5112 CheckConvert(saved_dst, saved_src, length, changed);
5113#endif
5114 return changed;
5115 }
5116
5117#ifdef DEBUG
5118 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5119 bool expected_changed = false;
5120 for (int i = 0; i < length; i++) {
5121 if (dst[i] == src[i]) continue;
5122 expected_changed = true;
5123 if (dir == ASCII_TO_LOWER) {
5124 ASSERT('A' <= src[i] && src[i] <= 'Z');
5125 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5126 } else {
5127 ASSERT(dir == ASCII_TO_UPPER);
5128 ASSERT('a' <= src[i] && src[i] <= 'z');
5129 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5130 }
5131 }
5132 ASSERT(expected_changed == changed);
5133 }
5134#endif
5135};
5136
5137
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005138struct ToLowerTraits {
5139 typedef unibrow::ToLowercase UnibrowConverter;
5140
lrn@chromium.org303ada72010-10-27 09:33:13 +00005141 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005142};
5143
5144
5145struct ToUpperTraits {
5146 typedef unibrow::ToUppercase UnibrowConverter;
5147
lrn@chromium.org303ada72010-10-27 09:33:13 +00005148 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005149};
5150
5151} // namespace
5152
5153
5154template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005155MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005156 Arguments args,
5157 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005158 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005159 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005160 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005161
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005162 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005163 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005164 if (length == 0) return s;
5165
5166 // Simpler handling of ascii strings.
5167 //
5168 // NOTE: This assumes that the upper/lower case of an ascii
5169 // character is also ascii. This is currently the case, but it
5170 // might break in the future if we implement more context and locale
5171 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005172 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005173 Object* o;
5174 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
5175 if (!maybe_o->ToObject(&o)) return maybe_o;
5176 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005177 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005178 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005179 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005180 return has_changed_character ? result : s;
5181 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005182
lrn@chromium.org303ada72010-10-27 09:33:13 +00005183 Object* answer;
5184 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
5185 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5186 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005187 if (answer->IsSmi()) {
5188 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005189 { MaybeObject* maybe_answer =
5190 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
5191 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5192 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005193 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005194 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005195}
5196
5197
lrn@chromium.org303ada72010-10-27 09:33:13 +00005198static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005199 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005200}
5201
5202
lrn@chromium.org303ada72010-10-27 09:33:13 +00005203static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005204 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005205}
5206
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005207
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005208static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5209 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5210}
5211
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005212
lrn@chromium.org303ada72010-10-27 09:33:13 +00005213static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005214 NoHandleAllocation ha;
5215 ASSERT(args.length() == 3);
5216
5217 CONVERT_CHECKED(String, s, args[0]);
5218 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5219 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5220
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005221 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005222 int length = s->length();
5223
5224 int left = 0;
5225 if (trimLeft) {
5226 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5227 left++;
5228 }
5229 }
5230
5231 int right = length;
5232 if (trimRight) {
5233 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5234 right--;
5235 }
5236 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005237 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005238}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005239
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005240
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005241template <typename SubjectChar, typename PatternChar>
5242void FindStringIndices(Vector<const SubjectChar> subject,
5243 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005244 ZoneList<int>* indices,
5245 unsigned int limit) {
5246 ASSERT(limit > 0);
5247 // Collect indices of pattern in subject, and the end-of-string index.
5248 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005249 StringSearch<PatternChar, SubjectChar> search(pattern);
5250 int pattern_length = pattern.length();
5251 int index = 0;
5252 while (limit > 0) {
5253 index = search.Search(subject, index);
5254 if (index < 0) return;
5255 indices->Add(index);
5256 index += pattern_length;
5257 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005258 }
5259}
5260
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005261
lrn@chromium.org303ada72010-10-27 09:33:13 +00005262static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005263 ASSERT(args.length() == 3);
5264 HandleScope handle_scope;
5265 CONVERT_ARG_CHECKED(String, subject, 0);
5266 CONVERT_ARG_CHECKED(String, pattern, 1);
5267 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5268
5269 int subject_length = subject->length();
5270 int pattern_length = pattern->length();
5271 RUNTIME_ASSERT(pattern_length > 0);
5272
5273 // The limit can be very large (0xffffffffu), but since the pattern
5274 // isn't empty, we can never create more parts than ~half the length
5275 // of the subject.
5276
5277 if (!subject->IsFlat()) FlattenString(subject);
5278
5279 static const int kMaxInitialListCapacity = 16;
5280
5281 ZoneScope scope(DELETE_ON_EXIT);
5282
5283 // Find (up to limit) indices of separator and end-of-string in subject
5284 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5285 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005286 if (!pattern->IsFlat()) FlattenString(pattern);
5287
5288 // No allocation block.
5289 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005290 AssertNoAllocation nogc;
5291 if (subject->IsAsciiRepresentation()) {
5292 Vector<const char> subject_vector = subject->ToAsciiVector();
5293 if (pattern->IsAsciiRepresentation()) {
5294 FindStringIndices(subject_vector,
5295 pattern->ToAsciiVector(),
5296 &indices,
5297 limit);
5298 } else {
5299 FindStringIndices(subject_vector,
5300 pattern->ToUC16Vector(),
5301 &indices,
5302 limit);
5303 }
5304 } else {
5305 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5306 if (pattern->IsAsciiRepresentation()) {
5307 FindStringIndices(subject_vector,
5308 pattern->ToAsciiVector(),
5309 &indices,
5310 limit);
5311 } else {
5312 FindStringIndices(subject_vector,
5313 pattern->ToUC16Vector(),
5314 &indices,
5315 limit);
5316 }
5317 }
5318 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005319
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005320 if (static_cast<uint32_t>(indices.length()) < limit) {
5321 indices.Add(subject_length);
5322 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005323
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005324 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005325
5326 // Create JSArray of substrings separated by separator.
5327 int part_count = indices.length();
5328
5329 Handle<JSArray> result = Factory::NewJSArray(part_count);
5330 result->set_length(Smi::FromInt(part_count));
5331
5332 ASSERT(result->HasFastElements());
5333
5334 if (part_count == 1 && indices.at(0) == subject_length) {
5335 FixedArray::cast(result->elements())->set(0, *subject);
5336 return *result;
5337 }
5338
5339 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5340 int part_start = 0;
5341 for (int i = 0; i < part_count; i++) {
5342 HandleScope local_loop_handle;
5343 int part_end = indices.at(i);
5344 Handle<String> substring =
5345 Factory::NewSubString(subject, part_start, part_end);
5346 elements->set(i, *substring);
5347 part_start = part_end + pattern_length;
5348 }
5349
5350 return *result;
5351}
5352
5353
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005354// Copies ascii characters to the given fixed array looking up
5355// one-char strings in the cache. Gives up on the first char that is
5356// not in the cache and fills the remainder with smi zeros. Returns
5357// the length of the successfully copied prefix.
5358static int CopyCachedAsciiCharsToArray(const char* chars,
5359 FixedArray* elements,
5360 int length) {
5361 AssertNoAllocation nogc;
5362 FixedArray* ascii_cache = Heap::single_character_string_cache();
5363 Object* undefined = Heap::undefined_value();
5364 int i;
5365 for (i = 0; i < length; ++i) {
5366 Object* value = ascii_cache->get(chars[i]);
5367 if (value == undefined) break;
5368 ASSERT(!Heap::InNewSpace(value));
5369 elements->set(i, value, SKIP_WRITE_BARRIER);
5370 }
5371 if (i < length) {
5372 ASSERT(Smi::FromInt(0) == 0);
5373 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5374 }
5375#ifdef DEBUG
5376 for (int j = 0; j < length; ++j) {
5377 Object* element = elements->get(j);
5378 ASSERT(element == Smi::FromInt(0) ||
5379 (element->IsString() && String::cast(element)->LooksValid()));
5380 }
5381#endif
5382 return i;
5383}
5384
5385
5386// Converts a String to JSArray.
5387// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005388static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005389 HandleScope scope;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005390 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005391 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005392 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005393
5394 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005395 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005396
5397 Handle<FixedArray> elements;
5398 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005399 Object* obj;
5400 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5401 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5402 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005403 elements = Handle<FixedArray>(FixedArray::cast(obj));
5404
5405 Vector<const char> chars = s->ToAsciiVector();
5406 // Note, this will initialize all elements (not only the prefix)
5407 // to prevent GC from seeing partially initialized array.
5408 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5409 *elements,
5410 length);
5411
5412 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005413 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5414 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005415 }
5416 } else {
5417 elements = Factory::NewFixedArray(length);
5418 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005419 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5420 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005421 }
5422 }
5423
5424#ifdef DEBUG
5425 for (int i = 0; i < length; ++i) {
5426 ASSERT(String::cast(elements->get(i))->length() == 1);
5427 }
5428#endif
5429
5430 return *Factory::NewJSArrayWithElements(elements);
5431}
5432
5433
lrn@chromium.org303ada72010-10-27 09:33:13 +00005434static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005435 NoHandleAllocation ha;
5436 ASSERT(args.length() == 1);
5437 CONVERT_CHECKED(String, value, args[0]);
5438 return value->ToObject();
5439}
5440
5441
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005442bool Runtime::IsUpperCaseChar(uint16_t ch) {
5443 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5444 int char_length = to_upper_mapping.get(ch, 0, chars);
5445 return char_length == 0;
5446}
5447
5448
lrn@chromium.org303ada72010-10-27 09:33:13 +00005449static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005450 NoHandleAllocation ha;
5451 ASSERT(args.length() == 1);
5452
5453 Object* number = args[0];
5454 RUNTIME_ASSERT(number->IsNumber());
5455
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005456 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005457}
5458
5459
lrn@chromium.org303ada72010-10-27 09:33:13 +00005460static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005461 NoHandleAllocation ha;
5462 ASSERT(args.length() == 1);
5463
5464 Object* number = args[0];
5465 RUNTIME_ASSERT(number->IsNumber());
5466
5467 return Heap::NumberToString(number, false);
5468}
5469
5470
lrn@chromium.org303ada72010-10-27 09:33:13 +00005471static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005472 NoHandleAllocation ha;
5473 ASSERT(args.length() == 1);
5474
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005475 CONVERT_DOUBLE_CHECKED(number, args[0]);
5476
5477 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5478 if (number > 0 && number <= Smi::kMaxValue) {
5479 return Smi::FromInt(static_cast<int>(number));
5480 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005481 return Heap::NumberFromDouble(DoubleToInteger(number));
5482}
5483
5484
lrn@chromium.org303ada72010-10-27 09:33:13 +00005485static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005486 NoHandleAllocation ha;
5487 ASSERT(args.length() == 1);
5488
5489 CONVERT_DOUBLE_CHECKED(number, args[0]);
5490
5491 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5492 if (number > 0 && number <= Smi::kMaxValue) {
5493 return Smi::FromInt(static_cast<int>(number));
5494 }
5495
5496 double double_value = DoubleToInteger(number);
5497 // Map both -0 and +0 to +0.
5498 if (double_value == 0) double_value = 0;
5499
5500 return Heap::NumberFromDouble(double_value);
5501}
5502
5503
lrn@chromium.org303ada72010-10-27 09:33:13 +00005504static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005505 NoHandleAllocation ha;
5506 ASSERT(args.length() == 1);
5507
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005508 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005509 return Heap::NumberFromUint32(number);
5510}
5511
5512
lrn@chromium.org303ada72010-10-27 09:33:13 +00005513static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005514 NoHandleAllocation ha;
5515 ASSERT(args.length() == 1);
5516
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005517 CONVERT_DOUBLE_CHECKED(number, args[0]);
5518
5519 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5520 if (number > 0 && number <= Smi::kMaxValue) {
5521 return Smi::FromInt(static_cast<int>(number));
5522 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005523 return Heap::NumberFromInt32(DoubleToInt32(number));
5524}
5525
5526
ager@chromium.org870a0b62008-11-04 11:43:05 +00005527// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5528// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005529static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005530 NoHandleAllocation ha;
5531 ASSERT(args.length() == 1);
5532
5533 Object* obj = args[0];
5534 if (obj->IsSmi()) {
5535 return obj;
5536 }
5537 if (obj->IsHeapNumber()) {
5538 double value = HeapNumber::cast(obj)->value();
5539 int int_value = FastD2I(value);
5540 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5541 return Smi::FromInt(int_value);
5542 }
5543 }
5544 return Heap::nan_value();
5545}
5546
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005547
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005548static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
5549 NoHandleAllocation ha;
5550 ASSERT(args.length() == 0);
5551 return Heap::AllocateHeapNumber(0);
5552}
5553
5554
lrn@chromium.org303ada72010-10-27 09:33:13 +00005555static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005556 NoHandleAllocation ha;
5557 ASSERT(args.length() == 2);
5558
5559 CONVERT_DOUBLE_CHECKED(x, args[0]);
5560 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005561 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005562}
5563
5564
lrn@chromium.org303ada72010-10-27 09:33:13 +00005565static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005566 NoHandleAllocation ha;
5567 ASSERT(args.length() == 2);
5568
5569 CONVERT_DOUBLE_CHECKED(x, args[0]);
5570 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005571 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005572}
5573
5574
lrn@chromium.org303ada72010-10-27 09:33:13 +00005575static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005576 NoHandleAllocation ha;
5577 ASSERT(args.length() == 2);
5578
5579 CONVERT_DOUBLE_CHECKED(x, args[0]);
5580 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005581 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005582}
5583
5584
lrn@chromium.org303ada72010-10-27 09:33:13 +00005585static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005586 NoHandleAllocation ha;
5587 ASSERT(args.length() == 1);
5588
5589 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005590 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005591}
5592
5593
lrn@chromium.org303ada72010-10-27 09:33:13 +00005594static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005595 NoHandleAllocation ha;
5596 ASSERT(args.length() == 0);
5597
5598 return Heap::NumberFromDouble(9876543210.0);
5599}
5600
5601
lrn@chromium.org303ada72010-10-27 09:33:13 +00005602static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005603 NoHandleAllocation ha;
5604 ASSERT(args.length() == 2);
5605
5606 CONVERT_DOUBLE_CHECKED(x, args[0]);
5607 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005608 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005609}
5610
5611
lrn@chromium.org303ada72010-10-27 09:33:13 +00005612static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005613 NoHandleAllocation ha;
5614 ASSERT(args.length() == 2);
5615
5616 CONVERT_DOUBLE_CHECKED(x, args[0]);
5617 CONVERT_DOUBLE_CHECKED(y, args[1]);
5618
ager@chromium.org3811b432009-10-28 14:53:37 +00005619 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005620 // NumberFromDouble may return a Smi instead of a Number object
5621 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005622}
5623
5624
lrn@chromium.org303ada72010-10-27 09:33:13 +00005625static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005626 NoHandleAllocation ha;
5627 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005628 CONVERT_CHECKED(String, str1, args[0]);
5629 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005630 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005631 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005632}
5633
5634
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005635template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005636static inline void StringBuilderConcatHelper(String* special,
5637 sinkchar* sink,
5638 FixedArray* fixed_array,
5639 int array_length) {
5640 int position = 0;
5641 for (int i = 0; i < array_length; i++) {
5642 Object* element = fixed_array->get(i);
5643 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005644 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005645 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005646 int pos;
5647 int len;
5648 if (encoded_slice > 0) {
5649 // Position and length encoded in one smi.
5650 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5651 len = StringBuilderSubstringLength::decode(encoded_slice);
5652 } else {
5653 // Position and length encoded in two smis.
5654 Object* obj = fixed_array->get(++i);
5655 ASSERT(obj->IsSmi());
5656 pos = Smi::cast(obj)->value();
5657 len = -encoded_slice;
5658 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005659 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005660 sink + position,
5661 pos,
5662 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005663 position += len;
5664 } else {
5665 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005666 int element_length = string->length();
5667 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005668 position += element_length;
5669 }
5670 }
5671}
5672
5673
lrn@chromium.org303ada72010-10-27 09:33:13 +00005674static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005675 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005676 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005677 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005678 if (!args[1]->IsSmi()) {
5679 Top::context()->mark_out_of_memory();
5680 return Failure::OutOfMemoryException();
5681 }
5682 int array_length = Smi::cast(args[1])->value();
5683 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005684
5685 // This assumption is used by the slice encoding in one or two smis.
5686 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5687
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005688 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005689 if (!array->HasFastElements()) {
5690 return Top::Throw(Heap::illegal_argument_symbol());
5691 }
5692 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005693 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005694 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005695 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005696
5697 if (array_length == 0) {
5698 return Heap::empty_string();
5699 } else if (array_length == 1) {
5700 Object* first = fixed_array->get(0);
5701 if (first->IsString()) return first;
5702 }
5703
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005704 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005705 int position = 0;
5706 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005707 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005708 Object* elt = fixed_array->get(i);
5709 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005710 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005711 int smi_value = Smi::cast(elt)->value();
5712 int pos;
5713 int len;
5714 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005715 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005716 pos = StringBuilderSubstringPosition::decode(smi_value);
5717 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005718 } else {
5719 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005720 len = -smi_value;
5721 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005722 i++;
5723 if (i >= array_length) {
5724 return Top::Throw(Heap::illegal_argument_symbol());
5725 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005726 Object* next_smi = fixed_array->get(i);
5727 if (!next_smi->IsSmi()) {
5728 return Top::Throw(Heap::illegal_argument_symbol());
5729 }
5730 pos = Smi::cast(next_smi)->value();
5731 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005732 return Top::Throw(Heap::illegal_argument_symbol());
5733 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005734 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005735 ASSERT(pos >= 0);
5736 ASSERT(len >= 0);
5737 if (pos > special_length || len > special_length - pos) {
5738 return Top::Throw(Heap::illegal_argument_symbol());
5739 }
5740 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005741 } else if (elt->IsString()) {
5742 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005743 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005744 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005745 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005746 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005747 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005748 } else {
5749 return Top::Throw(Heap::illegal_argument_symbol());
5750 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005751 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005752 Top::context()->mark_out_of_memory();
5753 return Failure::OutOfMemoryException();
5754 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005755 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005756 }
5757
5758 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005759 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005760
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005761 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005762 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5763 if (!maybe_object->ToObject(&object)) return maybe_object;
5764 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005765 SeqAsciiString* answer = SeqAsciiString::cast(object);
5766 StringBuilderConcatHelper(special,
5767 answer->GetChars(),
5768 fixed_array,
5769 array_length);
5770 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005771 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005772 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5773 if (!maybe_object->ToObject(&object)) return maybe_object;
5774 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005775 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5776 StringBuilderConcatHelper(special,
5777 answer->GetChars(),
5778 fixed_array,
5779 array_length);
5780 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005781 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005782}
5783
5784
lrn@chromium.org303ada72010-10-27 09:33:13 +00005785static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005786 NoHandleAllocation ha;
5787 ASSERT(args.length() == 2);
5788
5789 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5790 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5791 return Heap::NumberFromInt32(x | y);
5792}
5793
5794
lrn@chromium.org303ada72010-10-27 09:33:13 +00005795static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005796 NoHandleAllocation ha;
5797 ASSERT(args.length() == 2);
5798
5799 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5800 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5801 return Heap::NumberFromInt32(x & y);
5802}
5803
5804
lrn@chromium.org303ada72010-10-27 09:33:13 +00005805static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005806 NoHandleAllocation ha;
5807 ASSERT(args.length() == 2);
5808
5809 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5810 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5811 return Heap::NumberFromInt32(x ^ y);
5812}
5813
5814
lrn@chromium.org303ada72010-10-27 09:33:13 +00005815static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005816 NoHandleAllocation ha;
5817 ASSERT(args.length() == 1);
5818
5819 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5820 return Heap::NumberFromInt32(~x);
5821}
5822
5823
lrn@chromium.org303ada72010-10-27 09:33:13 +00005824static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005825 NoHandleAllocation ha;
5826 ASSERT(args.length() == 2);
5827
5828 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5829 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5830 return Heap::NumberFromInt32(x << (y & 0x1f));
5831}
5832
5833
lrn@chromium.org303ada72010-10-27 09:33:13 +00005834static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005835 NoHandleAllocation ha;
5836 ASSERT(args.length() == 2);
5837
5838 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5839 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5840 return Heap::NumberFromUint32(x >> (y & 0x1f));
5841}
5842
5843
lrn@chromium.org303ada72010-10-27 09:33:13 +00005844static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005845 NoHandleAllocation ha;
5846 ASSERT(args.length() == 2);
5847
5848 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5849 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5850 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5851}
5852
5853
lrn@chromium.org303ada72010-10-27 09:33:13 +00005854static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005855 NoHandleAllocation ha;
5856 ASSERT(args.length() == 2);
5857
5858 CONVERT_DOUBLE_CHECKED(x, args[0]);
5859 CONVERT_DOUBLE_CHECKED(y, args[1]);
5860 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5861 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5862 if (x == y) return Smi::FromInt(EQUAL);
5863 Object* result;
5864 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5865 result = Smi::FromInt(EQUAL);
5866 } else {
5867 result = Smi::FromInt(NOT_EQUAL);
5868 }
5869 return result;
5870}
5871
5872
lrn@chromium.org303ada72010-10-27 09:33:13 +00005873static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005874 NoHandleAllocation ha;
5875 ASSERT(args.length() == 2);
5876
5877 CONVERT_CHECKED(String, x, args[0]);
5878 CONVERT_CHECKED(String, y, args[1]);
5879
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005880 bool not_equal = !x->Equals(y);
5881 // This is slightly convoluted because the value that signifies
5882 // equality is 0 and inequality is 1 so we have to negate the result
5883 // from String::Equals.
5884 ASSERT(not_equal == 0 || not_equal == 1);
5885 STATIC_CHECK(EQUAL == 0);
5886 STATIC_CHECK(NOT_EQUAL == 1);
5887 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005888}
5889
5890
lrn@chromium.org303ada72010-10-27 09:33:13 +00005891static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005892 NoHandleAllocation ha;
5893 ASSERT(args.length() == 3);
5894
5895 CONVERT_DOUBLE_CHECKED(x, args[0]);
5896 CONVERT_DOUBLE_CHECKED(y, args[1]);
5897 if (isnan(x) || isnan(y)) return args[2];
5898 if (x == y) return Smi::FromInt(EQUAL);
5899 if (isless(x, y)) return Smi::FromInt(LESS);
5900 return Smi::FromInt(GREATER);
5901}
5902
5903
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005904// Compare two Smis as if they were converted to strings and then
5905// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005906static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005907 NoHandleAllocation ha;
5908 ASSERT(args.length() == 2);
5909
5910 // Arrays for the individual characters of the two Smis. Smis are
5911 // 31 bit integers and 10 decimal digits are therefore enough.
5912 static int x_elms[10];
5913 static int y_elms[10];
5914
5915 // Extract the integer values from the Smis.
5916 CONVERT_CHECKED(Smi, x, args[0]);
5917 CONVERT_CHECKED(Smi, y, args[1]);
5918 int x_value = x->value();
5919 int y_value = y->value();
5920
5921 // If the integers are equal so are the string representations.
5922 if (x_value == y_value) return Smi::FromInt(EQUAL);
5923
5924 // If one of the integers are zero the normal integer order is the
5925 // same as the lexicographic order of the string representations.
5926 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5927
ager@chromium.org32912102009-01-16 10:38:43 +00005928 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005929 // smallest because the char code of '-' is less than the char code
5930 // of any digit. Otherwise, we make both values positive.
5931 if (x_value < 0 || y_value < 0) {
5932 if (y_value >= 0) return Smi::FromInt(LESS);
5933 if (x_value >= 0) return Smi::FromInt(GREATER);
5934 x_value = -x_value;
5935 y_value = -y_value;
5936 }
5937
5938 // Convert the integers to arrays of their decimal digits.
5939 int x_index = 0;
5940 int y_index = 0;
5941 while (x_value > 0) {
5942 x_elms[x_index++] = x_value % 10;
5943 x_value /= 10;
5944 }
5945 while (y_value > 0) {
5946 y_elms[y_index++] = y_value % 10;
5947 y_value /= 10;
5948 }
5949
5950 // Loop through the arrays of decimal digits finding the first place
5951 // where they differ.
5952 while (--x_index >= 0 && --y_index >= 0) {
5953 int diff = x_elms[x_index] - y_elms[y_index];
5954 if (diff != 0) return Smi::FromInt(diff);
5955 }
5956
5957 // If one array is a suffix of the other array, the longest array is
5958 // the representation of the largest of the Smis in the
5959 // lexicographic ordering.
5960 return Smi::FromInt(x_index - y_index);
5961}
5962
5963
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005964static Object* StringInputBufferCompare(String* x, String* y) {
5965 static StringInputBuffer bufx;
5966 static StringInputBuffer bufy;
5967 bufx.Reset(x);
5968 bufy.Reset(y);
5969 while (bufx.has_more() && bufy.has_more()) {
5970 int d = bufx.GetNext() - bufy.GetNext();
5971 if (d < 0) return Smi::FromInt(LESS);
5972 else if (d > 0) return Smi::FromInt(GREATER);
5973 }
5974
5975 // x is (non-trivial) prefix of y:
5976 if (bufy.has_more()) return Smi::FromInt(LESS);
5977 // y is prefix of x:
5978 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
5979}
5980
5981
5982static Object* FlatStringCompare(String* x, String* y) {
5983 ASSERT(x->IsFlat());
5984 ASSERT(y->IsFlat());
5985 Object* equal_prefix_result = Smi::FromInt(EQUAL);
5986 int prefix_length = x->length();
5987 if (y->length() < prefix_length) {
5988 prefix_length = y->length();
5989 equal_prefix_result = Smi::FromInt(GREATER);
5990 } else if (y->length() > prefix_length) {
5991 equal_prefix_result = Smi::FromInt(LESS);
5992 }
5993 int r;
5994 if (x->IsAsciiRepresentation()) {
5995 Vector<const char> x_chars = x->ToAsciiVector();
5996 if (y->IsAsciiRepresentation()) {
5997 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005998 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005999 } else {
6000 Vector<const uc16> y_chars = y->ToUC16Vector();
6001 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6002 }
6003 } else {
6004 Vector<const uc16> x_chars = x->ToUC16Vector();
6005 if (y->IsAsciiRepresentation()) {
6006 Vector<const char> y_chars = y->ToAsciiVector();
6007 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6008 } else {
6009 Vector<const uc16> y_chars = y->ToUC16Vector();
6010 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6011 }
6012 }
6013 Object* result;
6014 if (r == 0) {
6015 result = equal_prefix_result;
6016 } else {
6017 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6018 }
6019 ASSERT(result == StringInputBufferCompare(x, y));
6020 return result;
6021}
6022
6023
lrn@chromium.org303ada72010-10-27 09:33:13 +00006024static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006025 NoHandleAllocation ha;
6026 ASSERT(args.length() == 2);
6027
6028 CONVERT_CHECKED(String, x, args[0]);
6029 CONVERT_CHECKED(String, y, args[1]);
6030
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006031 Counters::string_compare_runtime.Increment();
6032
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006033 // A few fast case tests before we flatten.
6034 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006035 if (y->length() == 0) {
6036 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006037 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006038 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006039 return Smi::FromInt(LESS);
6040 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006041
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006042 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006043 if (d < 0) return Smi::FromInt(LESS);
6044 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006045
lrn@chromium.org303ada72010-10-27 09:33:13 +00006046 Object* obj;
6047 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
6048 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6049 }
6050 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
6051 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6052 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006054 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
6055 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006056}
6057
6058
lrn@chromium.org303ada72010-10-27 09:33:13 +00006059static MaybeObject* Runtime_Math_acos(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_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006063
6064 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006065 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006066}
6067
6068
lrn@chromium.org303ada72010-10-27 09:33:13 +00006069static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006070 NoHandleAllocation ha;
6071 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006072 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006073
6074 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006075 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006076}
6077
6078
lrn@chromium.org303ada72010-10-27 09:33:13 +00006079static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006080 NoHandleAllocation ha;
6081 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006082 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006083
6084 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006085 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006086}
6087
6088
lrn@chromium.org303ada72010-10-27 09:33:13 +00006089static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006090 NoHandleAllocation ha;
6091 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006092 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006093
6094 CONVERT_DOUBLE_CHECKED(x, args[0]);
6095 CONVERT_DOUBLE_CHECKED(y, args[1]);
6096 double result;
6097 if (isinf(x) && isinf(y)) {
6098 // Make sure that the result in case of two infinite arguments
6099 // is a multiple of Pi / 4. The sign of the result is determined
6100 // by the first argument (x) and the sign of the second argument
6101 // determines the multiplier: one or three.
6102 static double kPiDividedBy4 = 0.78539816339744830962;
6103 int multiplier = (x < 0) ? -1 : 1;
6104 if (y < 0) multiplier *= 3;
6105 result = multiplier * kPiDividedBy4;
6106 } else {
6107 result = atan2(x, y);
6108 }
6109 return Heap::AllocateHeapNumber(result);
6110}
6111
6112
lrn@chromium.org303ada72010-10-27 09:33:13 +00006113static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006114 NoHandleAllocation ha;
6115 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006116 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006117
6118 CONVERT_DOUBLE_CHECKED(x, args[0]);
6119 return Heap::NumberFromDouble(ceiling(x));
6120}
6121
6122
lrn@chromium.org303ada72010-10-27 09:33:13 +00006123static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006124 NoHandleAllocation ha;
6125 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006126 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006127
6128 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006129 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006130}
6131
6132
lrn@chromium.org303ada72010-10-27 09:33:13 +00006133static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006134 NoHandleAllocation ha;
6135 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006136 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006137
6138 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006139 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006140}
6141
6142
lrn@chromium.org303ada72010-10-27 09:33:13 +00006143static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006144 NoHandleAllocation ha;
6145 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006146 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006147
6148 CONVERT_DOUBLE_CHECKED(x, args[0]);
6149 return Heap::NumberFromDouble(floor(x));
6150}
6151
6152
lrn@chromium.org303ada72010-10-27 09:33:13 +00006153static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006154 NoHandleAllocation ha;
6155 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006156 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006157
6158 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006159 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006160}
6161
6162
lrn@chromium.org303ada72010-10-27 09:33:13 +00006163static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006164 NoHandleAllocation ha;
6165 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006166 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006167
6168 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006169
6170 // If the second argument is a smi, it is much faster to call the
6171 // custom powi() function than the generic pow().
6172 if (args[1]->IsSmi()) {
6173 int y = Smi::cast(args[1])->value();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006174 return Heap::NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006175 }
6176
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006177 CONVERT_DOUBLE_CHECKED(y, args[1]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006178 return Heap::AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006179}
6180
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006181// Fast version of Math.pow if we know that y is not an integer and
6182// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006183static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006184 NoHandleAllocation ha;
6185 ASSERT(args.length() == 2);
6186 CONVERT_DOUBLE_CHECKED(x, args[0]);
6187 CONVERT_DOUBLE_CHECKED(y, args[1]);
6188 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006189 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006190 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006191 return Heap::nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006192 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006193 return Heap::AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006194 }
6195}
6196
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006197
lrn@chromium.org303ada72010-10-27 09:33:13 +00006198static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006199 NoHandleAllocation ha;
6200 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006201 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006202
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006203 if (!args[0]->IsHeapNumber()) {
6204 // Must be smi. Return the argument unchanged for all the other types
6205 // to make fuzz-natives test happy.
6206 return args[0];
6207 }
6208
6209 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6210
6211 double value = number->value();
6212 int exponent = number->get_exponent();
6213 int sign = number->get_sign();
6214
6215 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6216 // should be rounded to 2^30, which is not smi.
6217 if (!sign && exponent <= kSmiValueSize - 3) {
6218 return Smi::FromInt(static_cast<int>(value + 0.5));
6219 }
6220
6221 // If the magnitude is big enough, there's no place for fraction part. If we
6222 // try to add 0.5 to this number, 1.0 will be added instead.
6223 if (exponent >= 52) {
6224 return number;
6225 }
6226
6227 if (sign && value >= -0.5) return Heap::minus_zero_value();
6228
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006229 // Do not call NumberFromDouble() to avoid extra checks.
6230 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006231}
6232
6233
lrn@chromium.org303ada72010-10-27 09:33:13 +00006234static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006235 NoHandleAllocation ha;
6236 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006237 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006238
6239 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006240 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006241}
6242
6243
lrn@chromium.org303ada72010-10-27 09:33:13 +00006244static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006245 NoHandleAllocation ha;
6246 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006247 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006248
6249 CONVERT_DOUBLE_CHECKED(x, args[0]);
6250 return Heap::AllocateHeapNumber(sqrt(x));
6251}
6252
6253
lrn@chromium.org303ada72010-10-27 09:33:13 +00006254static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006255 NoHandleAllocation ha;
6256 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006257 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006258
6259 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006260 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006261}
6262
6263
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006264static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006265 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6266 181, 212, 243, 273, 304, 334};
6267 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6268 182, 213, 244, 274, 305, 335};
6269
6270 year += month / 12;
6271 month %= 12;
6272 if (month < 0) {
6273 year--;
6274 month += 12;
6275 }
6276
6277 ASSERT(month >= 0);
6278 ASSERT(month < 12);
6279
6280 // year_delta is an arbitrary number such that:
6281 // a) year_delta = -1 (mod 400)
6282 // b) year + year_delta > 0 for years in the range defined by
6283 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6284 // Jan 1 1970. This is required so that we don't run into integer
6285 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006286 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006287 // operations.
6288 static const int year_delta = 399999;
6289 static const int base_day = 365 * (1970 + year_delta) +
6290 (1970 + year_delta) / 4 -
6291 (1970 + year_delta) / 100 +
6292 (1970 + year_delta) / 400;
6293
6294 int year1 = year + year_delta;
6295 int day_from_year = 365 * year1 +
6296 year1 / 4 -
6297 year1 / 100 +
6298 year1 / 400 -
6299 base_day;
6300
6301 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006302 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006303 }
6304
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006305 return day_from_year + day_from_month_leap[month] + day - 1;
6306}
6307
6308
lrn@chromium.org303ada72010-10-27 09:33:13 +00006309static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006310 NoHandleAllocation ha;
6311 ASSERT(args.length() == 3);
6312
6313 CONVERT_SMI_CHECKED(year, args[0]);
6314 CONVERT_SMI_CHECKED(month, args[1]);
6315 CONVERT_SMI_CHECKED(date, args[2]);
6316
6317 return Smi::FromInt(MakeDay(year, month, date));
6318}
6319
6320
6321static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6322static const int kDaysIn4Years = 4 * 365 + 1;
6323static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6324static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6325static const int kDays1970to2000 = 30 * 365 + 7;
6326static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6327 kDays1970to2000;
6328static const int kYearsOffset = 400000;
6329
6330static const char kDayInYear[] = {
6331 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6332 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6333 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6334 22, 23, 24, 25, 26, 27, 28,
6335 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6336 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6337 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6338 22, 23, 24, 25, 26, 27, 28, 29, 30,
6339 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6340 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6341 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6342 22, 23, 24, 25, 26, 27, 28, 29, 30,
6343 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6344 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6345 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6346 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6347 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6348 22, 23, 24, 25, 26, 27, 28, 29, 30,
6349 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6350 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6351 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6352 22, 23, 24, 25, 26, 27, 28, 29, 30,
6353 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6354 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6355
6356 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6357 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6358 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6359 22, 23, 24, 25, 26, 27, 28,
6360 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6361 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6362 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6363 22, 23, 24, 25, 26, 27, 28, 29, 30,
6364 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6365 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6366 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6367 22, 23, 24, 25, 26, 27, 28, 29, 30,
6368 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6369 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6370 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6371 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6372 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6373 22, 23, 24, 25, 26, 27, 28, 29, 30,
6374 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6375 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6376 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6377 22, 23, 24, 25, 26, 27, 28, 29, 30,
6378 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6379 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6380
6381 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6382 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6383 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6384 22, 23, 24, 25, 26, 27, 28, 29,
6385 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6386 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6387 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6388 22, 23, 24, 25, 26, 27, 28, 29, 30,
6389 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6390 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6391 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6392 22, 23, 24, 25, 26, 27, 28, 29, 30,
6393 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6394 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6395 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6396 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6397 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6398 22, 23, 24, 25, 26, 27, 28, 29, 30,
6399 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6400 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6401 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6402 22, 23, 24, 25, 26, 27, 28, 29, 30,
6403 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6404 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6405
6406 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6407 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6408 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6409 22, 23, 24, 25, 26, 27, 28,
6410 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6411 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6412 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6413 22, 23, 24, 25, 26, 27, 28, 29, 30,
6414 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6415 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6416 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6417 22, 23, 24, 25, 26, 27, 28, 29, 30,
6418 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6419 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6420 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6421 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6422 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6423 22, 23, 24, 25, 26, 27, 28, 29, 30,
6424 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6425 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6426 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6427 22, 23, 24, 25, 26, 27, 28, 29, 30,
6428 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6429 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6430
6431static const char kMonthInYear[] = {
6432 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,
6433 0, 0, 0, 0, 0, 0,
6434 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,
6435 1, 1, 1,
6436 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,
6437 2, 2, 2, 2, 2, 2,
6438 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,
6439 3, 3, 3, 3, 3,
6440 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,
6441 4, 4, 4, 4, 4, 4,
6442 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,
6443 5, 5, 5, 5, 5,
6444 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,
6445 6, 6, 6, 6, 6, 6,
6446 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,
6447 7, 7, 7, 7, 7, 7,
6448 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,
6449 8, 8, 8, 8, 8,
6450 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,
6451 9, 9, 9, 9, 9, 9,
6452 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6453 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6454 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6455 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6456
6457 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,
6458 0, 0, 0, 0, 0, 0,
6459 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,
6460 1, 1, 1,
6461 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,
6462 2, 2, 2, 2, 2, 2,
6463 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,
6464 3, 3, 3, 3, 3,
6465 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,
6466 4, 4, 4, 4, 4, 4,
6467 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,
6468 5, 5, 5, 5, 5,
6469 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,
6470 6, 6, 6, 6, 6, 6,
6471 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,
6472 7, 7, 7, 7, 7, 7,
6473 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,
6474 8, 8, 8, 8, 8,
6475 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,
6476 9, 9, 9, 9, 9, 9,
6477 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6478 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6479 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6480 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6481
6482 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,
6483 0, 0, 0, 0, 0, 0,
6484 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,
6485 1, 1, 1, 1,
6486 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,
6487 2, 2, 2, 2, 2, 2,
6488 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,
6489 3, 3, 3, 3, 3,
6490 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,
6491 4, 4, 4, 4, 4, 4,
6492 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,
6493 5, 5, 5, 5, 5,
6494 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,
6495 6, 6, 6, 6, 6, 6,
6496 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,
6497 7, 7, 7, 7, 7, 7,
6498 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,
6499 8, 8, 8, 8, 8,
6500 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,
6501 9, 9, 9, 9, 9, 9,
6502 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6503 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6504 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6505 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6506
6507 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,
6508 0, 0, 0, 0, 0, 0,
6509 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,
6510 1, 1, 1,
6511 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,
6512 2, 2, 2, 2, 2, 2,
6513 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,
6514 3, 3, 3, 3, 3,
6515 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,
6516 4, 4, 4, 4, 4, 4,
6517 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,
6518 5, 5, 5, 5, 5,
6519 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,
6520 6, 6, 6, 6, 6, 6,
6521 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,
6522 7, 7, 7, 7, 7, 7,
6523 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,
6524 8, 8, 8, 8, 8,
6525 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,
6526 9, 9, 9, 9, 9, 9,
6527 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6528 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6529 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6530 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6531
6532
6533// This function works for dates from 1970 to 2099.
6534static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006535 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006536#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006537 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006538#endif
6539
6540 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6541 date %= kDaysIn4Years;
6542
6543 month = kMonthInYear[date];
6544 day = kDayInYear[date];
6545
6546 ASSERT(MakeDay(year, month, day) == save_date);
6547}
6548
6549
6550static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006551 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006552#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006553 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006554#endif
6555
6556 date += kDaysOffset;
6557 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6558 date %= kDaysIn400Years;
6559
6560 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6561
6562 date--;
6563 int yd1 = date / kDaysIn100Years;
6564 date %= kDaysIn100Years;
6565 year += 100 * yd1;
6566
6567 date++;
6568 int yd2 = date / kDaysIn4Years;
6569 date %= kDaysIn4Years;
6570 year += 4 * yd2;
6571
6572 date--;
6573 int yd3 = date / 365;
6574 date %= 365;
6575 year += yd3;
6576
6577 bool is_leap = (!yd1 || yd2) && !yd3;
6578
6579 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006580 ASSERT(is_leap || (date >= 0));
6581 ASSERT((date < 365) || (is_leap && (date < 366)));
6582 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6583 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6584 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006585
6586 if (is_leap) {
6587 day = kDayInYear[2*365 + 1 + date];
6588 month = kMonthInYear[2*365 + 1 + date];
6589 } else {
6590 day = kDayInYear[date];
6591 month = kMonthInYear[date];
6592 }
6593
6594 ASSERT(MakeDay(year, month, day) == save_date);
6595}
6596
6597
6598static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006599 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006600 if (date >= 0 && date < 32 * kDaysIn4Years) {
6601 DateYMDFromTimeAfter1970(date, year, month, day);
6602 } else {
6603 DateYMDFromTimeSlow(date, year, month, day);
6604 }
6605}
6606
6607
lrn@chromium.org303ada72010-10-27 09:33:13 +00006608static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006609 NoHandleAllocation ha;
6610 ASSERT(args.length() == 2);
6611
6612 CONVERT_DOUBLE_CHECKED(t, args[0]);
6613 CONVERT_CHECKED(JSArray, res_array, args[1]);
6614
6615 int year, month, day;
6616 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6617
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006618 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6619 FixedArray* elms = FixedArray::cast(res_array->elements());
6620 RUNTIME_ASSERT(elms->length() == 3);
6621
6622 elms->set(0, Smi::FromInt(year));
6623 elms->set(1, Smi::FromInt(month));
6624 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006625
6626 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006627}
6628
6629
lrn@chromium.org303ada72010-10-27 09:33:13 +00006630static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006631 NoHandleAllocation ha;
6632 ASSERT(args.length() == 3);
6633
6634 JSFunction* callee = JSFunction::cast(args[0]);
6635 Object** parameters = reinterpret_cast<Object**>(args[1]);
6636 const int length = Smi::cast(args[2])->value();
6637
lrn@chromium.org303ada72010-10-27 09:33:13 +00006638 Object* result;
6639 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6640 if (!maybe_result->ToObject(&result)) return maybe_result;
6641 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006642 // Allocate the elements if needed.
6643 if (length > 0) {
6644 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006645 Object* obj;
6646 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6647 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6648 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006649
6650 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006651 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6652 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006653 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006654
6655 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006656 for (int i = 0; i < length; i++) {
6657 array->set(i, *--parameters, mode);
6658 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006659 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006660 }
6661 return result;
6662}
6663
6664
lrn@chromium.org303ada72010-10-27 09:33:13 +00006665static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006666 HandleScope scope;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006667 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00006668 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006669 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006670 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006671
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006672 // Allocate global closures in old space and allocate local closures
6673 // in new space. Additionally pretenure closures that are assigned
6674 // directly to properties.
6675 pretenure = pretenure || (context->global_context() == *context);
6676 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006677 Handle<JSFunction> result =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006678 Factory::NewFunctionFromSharedFunctionInfo(shared,
6679 context,
6680 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006681 return *result;
6682}
6683
lrn@chromium.org303ada72010-10-27 09:33:13 +00006684static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006685 HandleScope scope;
6686 ASSERT(args.length() == 2);
6687 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6688 CONVERT_ARG_CHECKED(JSArray, params, 1);
6689
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006690 RUNTIME_ASSERT(params->HasFastElements());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006691 FixedArray* fixed = FixedArray::cast(params->elements());
6692
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006693 int fixed_length = Smi::cast(params->length())->value();
6694 SmartPointer<Object**> param_data(NewArray<Object**>(fixed_length));
6695 for (int i = 0; i < fixed_length; i++) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006696 Handle<Object> val = Handle<Object>(fixed->get(i));
6697 param_data[i] = val.location();
6698 }
6699
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006700 bool exception = false;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006701 Handle<Object> result = Execution::New(
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006702 function, fixed_length, *param_data, &exception);
6703 if (exception) {
6704 return Failure::Exception();
6705 }
6706 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006707 return *result;
6708}
6709
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006710
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006711static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006712 Handle<Object> prototype = Factory::null_value();
6713 if (function->has_instance_prototype()) {
6714 prototype = Handle<Object>(function->instance_prototype());
6715 }
6716 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006717 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006718 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006719 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006720 function->shared()->set_construct_stub(
6721 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006722 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006723 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006724}
6725
6726
lrn@chromium.org303ada72010-10-27 09:33:13 +00006727static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006728 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006729 ASSERT(args.length() == 1);
6730
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006731 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006732
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006733 // If the constructor isn't a proper function we throw a type error.
6734 if (!constructor->IsJSFunction()) {
6735 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6736 Handle<Object> type_error =
6737 Factory::NewTypeError("not_constructor", arguments);
6738 return Top::Throw(*type_error);
6739 }
6740
6741 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006742
6743 // If function should not have prototype, construction is not allowed. In this
6744 // case generated code bailouts here, since function has no initial_map.
6745 if (!function->should_have_prototype()) {
6746 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6747 Handle<Object> type_error =
6748 Factory::NewTypeError("not_constructor", arguments);
6749 return Top::Throw(*type_error);
6750 }
6751
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006752#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006753 // Handle stepping into constructors if step into is active.
6754 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006755 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006756 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006757#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006758
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006759 if (function->has_initial_map()) {
6760 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006761 // The 'Function' function ignores the receiver object when
6762 // called using 'new' and creates a new JSFunction object that
6763 // is returned. The receiver object is only used for error
6764 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006765 // JSFunction. Factory::NewJSObject() should not be used to
6766 // allocate JSFunctions since it does not properly initialize
6767 // the shared part of the function. Since the receiver is
6768 // ignored anyway, we use the global object as the receiver
6769 // instead of a new JSFunction object. This way, errors are
6770 // reported the same way whether or not 'Function' is called
6771 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006772 return Top::context()->global();
6773 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006774 }
6775
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006776 // The function should be compiled for the optimization hints to be
6777 // available. We cannot use EnsureCompiled because that forces a
6778 // compilation through the shared function info which makes it
6779 // impossible for us to optimize.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006780 Handle<SharedFunctionInfo> shared(function->shared());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006781 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006782
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006783 if (!function->has_initial_map() &&
6784 shared->IsInobjectSlackTrackingInProgress()) {
6785 // The tracking is already in progress for another function. We can only
6786 // track one initial_map at a time, so we force the completion before the
6787 // function is called as a constructor for the first time.
6788 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006789 }
6790
6791 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006792 Handle<JSObject> result = Factory::NewJSObject(function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006793 // Delay setting the stub if inobject slack tracking is in progress.
6794 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6795 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006796 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006797
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006798 Counters::constructed_objects.Increment();
6799 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006800
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006801 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006802}
6803
6804
lrn@chromium.org303ada72010-10-27 09:33:13 +00006805static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006806 HandleScope scope;
6807 ASSERT(args.length() == 1);
6808
6809 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6810 function->shared()->CompleteInobjectSlackTracking();
6811 TrySettingInlineConstructStub(function);
6812
6813 return Heap::undefined_value();
6814}
6815
6816
lrn@chromium.org303ada72010-10-27 09:33:13 +00006817static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006818 HandleScope scope;
6819 ASSERT(args.length() == 1);
6820
6821 Handle<JSFunction> function = args.at<JSFunction>(0);
6822#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006823 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006824 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006825 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006826 PrintF("]\n");
6827 }
6828#endif
6829
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006830 // Compile the target function. Here we compile using CompileLazyInLoop in
6831 // order to get the optimized version. This helps code like delta-blue
6832 // that calls performance-critical routines through constructors. A
6833 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6834 // direct call. Since the in-loop tracking takes place through CallICs
6835 // this means that things called through constructors are never known to
6836 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006837 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006838 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006839 return Failure::Exception();
6840 }
6841
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006842 // All done. Return the compiled code.
6843 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006844 return function->code();
6845}
6846
6847
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006848static MaybeObject* Runtime_LazyRecompile(Arguments args) {
6849 HandleScope scope;
6850 ASSERT(args.length() == 1);
6851 Handle<JSFunction> function = args.at<JSFunction>(0);
6852 // If the function is not optimizable or debugger is active continue using the
6853 // code from the full compiler.
6854 if (!function->shared()->code()->optimizable() ||
6855 Debug::has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006856 if (FLAG_trace_opt) {
6857 PrintF("[failed to optimize ");
6858 function->PrintName();
6859 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
6860 function->shared()->code()->optimizable() ? "T" : "F",
6861 Debug::has_break_points() ? "T" : "F");
6862 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006863 function->ReplaceCode(function->shared()->code());
6864 return function->code();
6865 }
6866 if (CompileOptimized(function, AstNode::kNoNumber)) {
6867 return function->code();
6868 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006869 if (FLAG_trace_opt) {
6870 PrintF("[failed to optimize ");
6871 function->PrintName();
6872 PrintF(": optimized compilation failed]\n");
6873 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006874 function->ReplaceCode(function->shared()->code());
6875 return Failure::Exception();
6876}
6877
6878
6879static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
6880 HandleScope scope;
6881 ASSERT(args.length() == 1);
6882 RUNTIME_ASSERT(args[0]->IsSmi());
6883 Deoptimizer::BailoutType type =
6884 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
6885 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6886 ASSERT(Heap::IsAllocationAllowed());
6887 int frames = deoptimizer->output_count();
6888
6889 JavaScriptFrameIterator it;
6890 JavaScriptFrame* frame = NULL;
6891 for (int i = 0; i < frames; i++) {
6892 if (i != 0) it.Advance();
6893 frame = it.frame();
6894 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
6895 }
6896 delete deoptimizer;
6897
6898 RUNTIME_ASSERT(frame->function()->IsJSFunction());
6899 Handle<JSFunction> function(JSFunction::cast(frame->function()));
6900 Handle<Object> arguments;
6901 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00006902 if (frame->GetExpression(i) == Heap::arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006903 if (arguments.is_null()) {
6904 // FunctionGetArguments can't throw an exception, so cast away the
6905 // doubt with an assert.
6906 arguments = Handle<Object>(
6907 Accessors::FunctionGetArguments(*function,
6908 NULL)->ToObjectUnchecked());
6909 ASSERT(*arguments != Heap::null_value());
6910 ASSERT(*arguments != Heap::undefined_value());
6911 }
6912 frame->SetExpression(i, *arguments);
6913 }
6914 }
6915
6916 CompilationCache::MarkForLazyOptimizing(function);
6917 if (type == Deoptimizer::EAGER) {
6918 RUNTIME_ASSERT(function->IsOptimized());
6919 } else {
6920 RUNTIME_ASSERT(!function->IsOptimized());
6921 }
6922
6923 // Avoid doing too much work when running with --always-opt and keep
6924 // the optimized code around.
6925 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
6926 return Heap::undefined_value();
6927 }
6928
6929 // Count the number of optimized activations of the function.
6930 int activations = 0;
6931 while (!it.done()) {
6932 JavaScriptFrame* frame = it.frame();
6933 if (frame->is_optimized() && frame->function() == *function) {
6934 activations++;
6935 }
6936 it.Advance();
6937 }
6938
6939 // TODO(kasperl): For now, we cannot support removing the optimized
6940 // code when we have recursive invocations of the same function.
6941 if (activations == 0) {
6942 if (FLAG_trace_deopt) {
6943 PrintF("[removing optimized code for: ");
6944 function->PrintName();
6945 PrintF("]\n");
6946 }
6947 function->ReplaceCode(function->shared()->code());
6948 }
6949 return Heap::undefined_value();
6950}
6951
6952
6953static MaybeObject* Runtime_NotifyOSR(Arguments args) {
6954 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6955 delete deoptimizer;
6956 return Heap::undefined_value();
6957}
6958
6959
6960static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
6961 HandleScope scope;
6962 ASSERT(args.length() == 1);
6963 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6964 if (!function->IsOptimized()) return Heap::undefined_value();
6965
6966 Deoptimizer::DeoptimizeFunction(*function);
6967
6968 return Heap::undefined_value();
6969}
6970
6971
6972static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
6973 HandleScope scope;
6974 ASSERT(args.length() == 1);
6975 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6976
6977 // We're not prepared to handle a function with arguments object.
6978 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
6979
6980 // We have hit a back edge in an unoptimized frame for a function that was
6981 // selected for on-stack replacement. Find the unoptimized code object.
6982 Handle<Code> unoptimized(function->shared()->code());
6983 // Keep track of whether we've succeeded in optimizing.
6984 bool succeeded = unoptimized->optimizable();
6985 if (succeeded) {
6986 // If we are trying to do OSR when there are already optimized
6987 // activations of the function, it means (a) the function is directly or
6988 // indirectly recursive and (b) an optimized invocation has been
6989 // deoptimized so that we are currently in an unoptimized activation.
6990 // Check for optimized activations of this function.
6991 JavaScriptFrameIterator it;
6992 while (succeeded && !it.done()) {
6993 JavaScriptFrame* frame = it.frame();
6994 succeeded = !frame->is_optimized() || frame->function() != *function;
6995 it.Advance();
6996 }
6997 }
6998
6999 int ast_id = AstNode::kNoNumber;
7000 if (succeeded) {
7001 // The top JS function is this one, the PC is somewhere in the
7002 // unoptimized code.
7003 JavaScriptFrameIterator it;
7004 JavaScriptFrame* frame = it.frame();
7005 ASSERT(frame->function() == *function);
7006 ASSERT(frame->code() == *unoptimized);
7007 ASSERT(unoptimized->contains(frame->pc()));
7008
7009 // Use linear search of the unoptimized code's stack check table to find
7010 // the AST id matching the PC.
7011 Address start = unoptimized->instruction_start();
7012 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007013 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007014 uint32_t table_length = Memory::uint32_at(table_cursor);
7015 table_cursor += kIntSize;
7016 for (unsigned i = 0; i < table_length; ++i) {
7017 // Table entries are (AST id, pc offset) pairs.
7018 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7019 if (pc_offset == target_pc_offset) {
7020 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7021 break;
7022 }
7023 table_cursor += 2 * kIntSize;
7024 }
7025 ASSERT(ast_id != AstNode::kNoNumber);
7026 if (FLAG_trace_osr) {
7027 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7028 function->PrintName();
7029 PrintF("]\n");
7030 }
7031
7032 // Try to compile the optimized code. A true return value from
7033 // CompileOptimized means that compilation succeeded, not necessarily
7034 // that optimization succeeded.
7035 if (CompileOptimized(function, ast_id) && function->IsOptimized()) {
7036 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7037 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007038 if (data->OsrPcOffset()->value() >= 0) {
7039 if (FLAG_trace_osr) {
7040 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007041 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007042 }
7043 ASSERT(data->OsrAstId()->value() == ast_id);
7044 } else {
7045 // We may never generate the desired OSR entry if we emit an
7046 // early deoptimize.
7047 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007048 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007049 } else {
7050 succeeded = false;
7051 }
7052 }
7053
7054 // Revert to the original stack checks in the original unoptimized code.
7055 if (FLAG_trace_osr) {
7056 PrintF("[restoring original stack checks in ");
7057 function->PrintName();
7058 PrintF("]\n");
7059 }
7060 StackCheckStub check_stub;
7061 Handle<Code> check_code = check_stub.GetCode();
7062 Handle<Code> replacement_code(
7063 Builtins::builtin(Builtins::OnStackReplacement));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007064 Deoptimizer::RevertStackCheckCode(*unoptimized,
7065 *check_code,
7066 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007067
7068 // Allow OSR only at nesting level zero again.
7069 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7070
7071 // If the optimization attempt succeeded, return the AST id tagged as a
7072 // smi. This tells the builtin that we need to translate the unoptimized
7073 // frame to an optimized one.
7074 if (succeeded) {
7075 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7076 return Smi::FromInt(ast_id);
7077 } else {
7078 return Smi::FromInt(-1);
7079 }
7080}
7081
7082
lrn@chromium.org303ada72010-10-27 09:33:13 +00007083static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007084 HandleScope scope;
7085 ASSERT(args.length() == 1);
7086 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7087 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7088}
7089
7090
lrn@chromium.org303ada72010-10-27 09:33:13 +00007091static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007092 HandleScope scope;
7093 ASSERT(args.length() == 1);
7094 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7095 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7096}
7097
7098
lrn@chromium.org303ada72010-10-27 09:33:13 +00007099static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007100 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007101 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007102
kasper.lund7276f142008-07-30 08:49:36 +00007103 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007104 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007105 Object* result;
7106 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
7107 if (!maybe_result->ToObject(&result)) return maybe_result;
7108 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007109
7110 Top::set_context(Context::cast(result));
7111
kasper.lund7276f142008-07-30 08:49:36 +00007112 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007113}
7114
lrn@chromium.org303ada72010-10-27 09:33:13 +00007115
7116MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
7117 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007118 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007119 Object* js_object = object;
7120 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007121 MaybeObject* maybe_js_object = js_object->ToObject();
7122 if (!maybe_js_object->ToObject(&js_object)) {
7123 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7124 return maybe_js_object;
7125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007126 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007127 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007128 Handle<Object> result =
7129 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
7130 return Top::Throw(*result);
7131 }
7132 }
7133
lrn@chromium.org303ada72010-10-27 09:33:13 +00007134 Object* result;
7135 { MaybeObject* maybe_result =
7136 Heap::AllocateWithContext(Top::context(),
7137 JSObject::cast(js_object),
7138 is_catch_context);
7139 if (!maybe_result->ToObject(&result)) return maybe_result;
7140 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007141
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007142 Context* context = Context::cast(result);
7143 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007144
kasper.lund7276f142008-07-30 08:49:36 +00007145 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007146}
7147
7148
lrn@chromium.org303ada72010-10-27 09:33:13 +00007149static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007150 NoHandleAllocation ha;
7151 ASSERT(args.length() == 1);
7152 return PushContextHelper(args[0], false);
7153}
7154
7155
lrn@chromium.org303ada72010-10-27 09:33:13 +00007156static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007157 NoHandleAllocation ha;
7158 ASSERT(args.length() == 1);
7159 return PushContextHelper(args[0], true);
7160}
7161
7162
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007163static MaybeObject* Runtime_DeleteContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007164 HandleScope scope;
7165 ASSERT(args.length() == 2);
7166
7167 CONVERT_ARG_CHECKED(Context, context, 0);
7168 CONVERT_ARG_CHECKED(String, name, 1);
7169
7170 int index;
7171 PropertyAttributes attributes;
7172 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007173 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007174
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007175 // If the slot was not found the result is true.
7176 if (holder.is_null()) {
7177 return Heap::true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007178 }
7179
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007180 // If the slot was found in a context, it should be DONT_DELETE.
7181 if (holder->IsContext()) {
7182 return Heap::false_value();
7183 }
7184
7185 // The slot was found in a JSObject, either a context extension object,
7186 // the global object, or an arguments object. Try to delete it
7187 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7188 // which allows deleting all parameters in functions that mention
7189 // 'arguments', we do this even for the case of slots found on an
7190 // arguments object. The slot was found on an arguments object if the
7191 // index is non-negative.
7192 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7193 if (index >= 0) {
7194 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7195 } else {
7196 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7197 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007198}
7199
7200
ager@chromium.orga1645e22009-09-09 19:27:10 +00007201// A mechanism to return a pair of Object pointers in registers (if possible).
7202// How this is achieved is calling convention-dependent.
7203// All currently supported x86 compiles uses calling conventions that are cdecl
7204// variants where a 64-bit value is returned in two 32-bit registers
7205// (edx:eax on ia32, r1:r0 on ARM).
7206// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7207// In Win64 calling convention, a struct of two pointers is returned in memory,
7208// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007209#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007210struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007211 MaybeObject* x;
7212 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007213};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007214
lrn@chromium.org303ada72010-10-27 09:33:13 +00007215static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007216 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007217 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7218 // In Win64 they are assigned to a hidden first argument.
7219 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007220}
7221#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007222typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007223static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007224 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007225 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007226}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007227#endif
7228
7229
lrn@chromium.org303ada72010-10-27 09:33:13 +00007230static inline MaybeObject* Unhole(MaybeObject* x,
7231 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007232 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7233 USE(attributes);
7234 return x->IsTheHole() ? Heap::undefined_value() : x;
7235}
7236
7237
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007238static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
7239 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007240 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007241 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007242 JSFunction* context_extension_function =
7243 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007244 // If the holder isn't a context extension object, we just return it
7245 // as the receiver. This allows arguments objects to be used as
7246 // receivers, but only if they are put in the context scope chain
7247 // explicitly via a with-statement.
7248 Object* constructor = holder->map()->constructor();
7249 if (constructor != context_extension_function) return holder;
7250 // Fall back to using the global object as the receiver if the
7251 // property turns out to be a local variable allocated in a context
7252 // extension object - introduced via eval.
7253 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007254}
7255
7256
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007257static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007258 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00007259 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007260
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007261 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00007262 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007263 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007264 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007265 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007266
7267 int index;
7268 PropertyAttributes attributes;
7269 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007270 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007271
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007272 // If the index is non-negative, the slot has been found in a local
7273 // variable or a parameter. Read it from the context object or the
7274 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007275 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007276 // If the "property" we were looking for is a local variable or an
7277 // argument in a context, the receiver is the global object; see
7278 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
7279 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007280 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007281 ? Context::cast(*holder)->get(index)
7282 : JSObject::cast(*holder)->GetElement(index);
7283 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007284 }
7285
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007286 // If the holder is found, we read the property from it.
7287 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007288 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007289 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007290 JSObject* receiver;
7291 if (object->IsGlobalObject()) {
7292 receiver = GlobalObject::cast(object)->global_receiver();
7293 } else if (context->is_exception_holder(*holder)) {
7294 receiver = Top::context()->global()->global_receiver();
7295 } else {
7296 receiver = ComputeReceiverForNonGlobal(object);
7297 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007298 // No need to unhole the value here. This is taken care of by the
7299 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007300 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007301 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007302 }
7303
7304 if (throw_error) {
7305 // The property doesn't exist - throw exception.
7306 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007307 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007308 return MakePair(Top::Throw(*reference_error), NULL);
7309 } else {
7310 // The property doesn't exist - return undefined
7311 return MakePair(Heap::undefined_value(), Heap::undefined_value());
7312 }
7313}
7314
7315
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007316static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007317 return LoadContextSlotHelper(args, true);
7318}
7319
7320
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007321static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007322 return LoadContextSlotHelper(args, false);
7323}
7324
7325
lrn@chromium.org303ada72010-10-27 09:33:13 +00007326static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007327 HandleScope scope;
7328 ASSERT(args.length() == 3);
7329
7330 Handle<Object> value(args[0]);
7331 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007332 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007333
7334 int index;
7335 PropertyAttributes attributes;
7336 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007337 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007338
7339 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007340 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007341 // Ignore if read_only variable.
7342 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007343 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007344 }
7345 } else {
7346 ASSERT((attributes & READ_ONLY) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007347 Handle<JSObject>::cast(holder)->SetElement(index, *value)->
7348 ToObjectUnchecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007349 }
7350 return *value;
7351 }
7352
7353 // Slow case: The property is not in a FixedArray context.
7354 // It is either in an JSObject extension context or it was not found.
7355 Handle<JSObject> context_ext;
7356
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007357 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007358 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007359 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007360 } else {
7361 // The property was not found. It needs to be stored in the global context.
7362 ASSERT(attributes == ABSENT);
7363 attributes = NONE;
7364 context_ext = Handle<JSObject>(Top::context()->global());
7365 }
7366
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007367 // Set the property, but ignore if read_only variable on the context
7368 // extension object itself.
7369 if ((attributes & READ_ONLY) == 0 ||
7370 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007371 Handle<Object> set = SetProperty(context_ext, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007372 if (set.is_null()) {
7373 // Failure::Exception is converted to a null handle in the
7374 // handle-based methods such as SetProperty. We therefore need
7375 // to convert null handles back to exceptions.
7376 ASSERT(Top::has_pending_exception());
7377 return Failure::Exception();
7378 }
7379 }
7380 return *value;
7381}
7382
7383
lrn@chromium.org303ada72010-10-27 09:33:13 +00007384static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007385 HandleScope scope;
7386 ASSERT(args.length() == 1);
7387
7388 return Top::Throw(args[0]);
7389}
7390
7391
lrn@chromium.org303ada72010-10-27 09:33:13 +00007392static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007393 HandleScope scope;
7394 ASSERT(args.length() == 1);
7395
7396 return Top::ReThrow(args[0]);
7397}
7398
7399
lrn@chromium.org303ada72010-10-27 09:33:13 +00007400static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007401 ASSERT_EQ(0, args.length());
7402 return Top::PromoteScheduledException();
7403}
7404
7405
lrn@chromium.org303ada72010-10-27 09:33:13 +00007406static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007407 HandleScope scope;
7408 ASSERT(args.length() == 1);
7409
7410 Handle<Object> name(args[0]);
7411 Handle<Object> reference_error =
7412 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7413 return Top::Throw(*reference_error);
7414}
7415
7416
lrn@chromium.org303ada72010-10-27 09:33:13 +00007417static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007418 NoHandleAllocation na;
7419 return Top::StackOverflow();
7420}
7421
7422
lrn@chromium.org303ada72010-10-27 09:33:13 +00007423static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007424 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007425
7426 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007427 if (StackGuard::IsStackOverflow()) {
7428 return Runtime_StackOverflow(args);
7429 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007430
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007431 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007432}
7433
7434
7435// NOTE: These PrintXXX functions are defined for all builds (not just
7436// DEBUG builds) because we may want to be able to trace function
7437// calls in all modes.
7438static void PrintString(String* str) {
7439 // not uncommon to have empty strings
7440 if (str->length() > 0) {
7441 SmartPointer<char> s =
7442 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7443 PrintF("%s", *s);
7444 }
7445}
7446
7447
7448static void PrintObject(Object* obj) {
7449 if (obj->IsSmi()) {
7450 PrintF("%d", Smi::cast(obj)->value());
7451 } else if (obj->IsString() || obj->IsSymbol()) {
7452 PrintString(String::cast(obj));
7453 } else if (obj->IsNumber()) {
7454 PrintF("%g", obj->Number());
7455 } else if (obj->IsFailure()) {
7456 PrintF("<failure>");
7457 } else if (obj->IsUndefined()) {
7458 PrintF("<undefined>");
7459 } else if (obj->IsNull()) {
7460 PrintF("<null>");
7461 } else if (obj->IsTrue()) {
7462 PrintF("<true>");
7463 } else if (obj->IsFalse()) {
7464 PrintF("<false>");
7465 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007466 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007467 }
7468}
7469
7470
7471static int StackSize() {
7472 int n = 0;
7473 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7474 return n;
7475}
7476
7477
7478static void PrintTransition(Object* result) {
7479 // indentation
7480 { const int nmax = 80;
7481 int n = StackSize();
7482 if (n <= nmax)
7483 PrintF("%4d:%*s", n, n, "");
7484 else
7485 PrintF("%4d:%*s", n, nmax, "...");
7486 }
7487
7488 if (result == NULL) {
7489 // constructor calls
7490 JavaScriptFrameIterator it;
7491 JavaScriptFrame* frame = it.frame();
7492 if (frame->IsConstructor()) PrintF("new ");
7493 // function name
7494 Object* fun = frame->function();
7495 if (fun->IsJSFunction()) {
7496 PrintObject(JSFunction::cast(fun)->shared()->name());
7497 } else {
7498 PrintObject(fun);
7499 }
7500 // function arguments
7501 // (we are intentionally only printing the actually
7502 // supplied parameters, not all parameters required)
7503 PrintF("(this=");
7504 PrintObject(frame->receiver());
7505 const int length = frame->GetProvidedParametersCount();
7506 for (int i = 0; i < length; i++) {
7507 PrintF(", ");
7508 PrintObject(frame->GetParameter(i));
7509 }
7510 PrintF(") {\n");
7511
7512 } else {
7513 // function result
7514 PrintF("} -> ");
7515 PrintObject(result);
7516 PrintF("\n");
7517 }
7518}
7519
7520
lrn@chromium.org303ada72010-10-27 09:33:13 +00007521static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007522 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007523 NoHandleAllocation ha;
7524 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007525 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007526}
7527
7528
lrn@chromium.org303ada72010-10-27 09:33:13 +00007529static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007530 NoHandleAllocation ha;
7531 PrintTransition(args[0]);
7532 return args[0]; // return TOS
7533}
7534
7535
lrn@chromium.org303ada72010-10-27 09:33:13 +00007536static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007537 NoHandleAllocation ha;
7538 ASSERT(args.length() == 1);
7539
7540#ifdef DEBUG
7541 if (args[0]->IsString()) {
7542 // If we have a string, assume it's a code "marker"
7543 // and print some interesting cpu debugging info.
7544 JavaScriptFrameIterator it;
7545 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007546 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7547 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007548 } else {
7549 PrintF("DebugPrint: ");
7550 }
7551 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007552 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007553 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007554 HeapObject::cast(args[0])->map()->Print();
7555 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007556#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007557 // ShortPrint is available in release mode. Print is not.
7558 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007559#endif
7560 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007561 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007562
7563 return args[0]; // return TOS
7564}
7565
7566
lrn@chromium.org303ada72010-10-27 09:33:13 +00007567static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007568 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007569 NoHandleAllocation ha;
7570 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007571 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007572}
7573
7574
lrn@chromium.org303ada72010-10-27 09:33:13 +00007575static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007576 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007577 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007578
7579 // According to ECMA-262, section 15.9.1, page 117, the precision of
7580 // the number in a Date object representing a particular instant in
7581 // time is milliseconds. Therefore, we floor the result of getting
7582 // the OS time.
7583 double millis = floor(OS::TimeCurrentMillis());
7584 return Heap::NumberFromDouble(millis);
7585}
7586
7587
lrn@chromium.org303ada72010-10-27 09:33:13 +00007588static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007589 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007590 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007591
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007592 CONVERT_ARG_CHECKED(String, str, 0);
7593 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007594
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007595 CONVERT_ARG_CHECKED(JSArray, output, 1);
7596 RUNTIME_ASSERT(output->HasFastElements());
7597
7598 AssertNoAllocation no_allocation;
7599
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007600 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007601 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7602 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007603 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007604 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007605 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007606 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007607 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7608 }
7609
7610 if (result) {
7611 return *output;
7612 } else {
7613 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007614 }
7615}
7616
7617
lrn@chromium.org303ada72010-10-27 09:33:13 +00007618static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007619 NoHandleAllocation ha;
7620 ASSERT(args.length() == 1);
7621
7622 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007623 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007624 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7625}
7626
7627
lrn@chromium.org303ada72010-10-27 09:33:13 +00007628static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007629 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007630 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007631
7632 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7633}
7634
7635
lrn@chromium.org303ada72010-10-27 09:33:13 +00007636static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007637 NoHandleAllocation ha;
7638 ASSERT(args.length() == 1);
7639
7640 CONVERT_DOUBLE_CHECKED(x, args[0]);
7641 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7642}
7643
7644
lrn@chromium.org303ada72010-10-27 09:33:13 +00007645static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007646 ASSERT(args.length() == 1);
7647 Object* global = args[0];
7648 if (!global->IsJSGlobalObject()) return Heap::null_value();
7649 return JSGlobalObject::cast(global)->global_receiver();
7650}
7651
7652
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007653static MaybeObject* Runtime_ParseJson(Arguments args) {
7654 HandleScope scope;
7655 ASSERT_EQ(1, args.length());
7656 CONVERT_ARG_CHECKED(String, source, 0);
7657
7658 Handle<Object> result = JsonParser::Parse(source);
7659 if (result.is_null()) {
7660 // Syntax error or stack overflow in scanner.
7661 ASSERT(Top::has_pending_exception());
7662 return Failure::Exception();
7663 }
7664 return *result;
7665}
7666
7667
lrn@chromium.org303ada72010-10-27 09:33:13 +00007668static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007669 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007670 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007671 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007672
ager@chromium.org381abbb2009-02-25 13:23:22 +00007673 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007674 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007675 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7676 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007677 true,
7678 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007679 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007680 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007681 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007682 return *fun;
7683}
7684
7685
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007686static ObjectPair CompileGlobalEval(Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007687 Handle<Object> receiver,
7688 StrictModeFlag mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007689 // Deal with a normal eval call with a string argument. Compile it
7690 // and return the compiled function bound in the local context.
7691 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7692 source,
7693 Handle<Context>(Top::context()),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007694 Top::context()->IsGlobalContext(),
7695 mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007696 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7697 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7698 shared,
7699 Handle<Context>(Top::context()),
7700 NOT_TENURED);
7701 return MakePair(*compiled, *receiver);
7702}
7703
7704
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007705static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007706 ASSERT(args.length() == 4);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007707 if (!args[0]->IsJSFunction()) {
7708 return MakePair(Top::ThrowIllegalOperation(), NULL);
7709 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007710
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007711 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007712 Handle<JSFunction> callee = args.at<JSFunction>(0);
7713 Handle<Object> receiver; // Will be overwritten.
7714
7715 // Compute the calling context.
7716 Handle<Context> context = Handle<Context>(Top::context());
7717#ifdef DEBUG
7718 // Make sure Top::context() agrees with the old code that traversed
7719 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007720 StackFrameLocator locator;
7721 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007722 ASSERT(Context::cast(frame->context()) == *context);
7723#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007724
7725 // Find where the 'eval' symbol is bound. It is unaliased only if
7726 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007727 int index = -1;
7728 PropertyAttributes attributes = ABSENT;
7729 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007730 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7731 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007732 // Stop search when eval is found or when the global context is
7733 // reached.
7734 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007735 if (context->is_function_context()) {
7736 context = Handle<Context>(Context::cast(context->closure()->context()));
7737 } else {
7738 context = Handle<Context>(context->previous());
7739 }
7740 }
7741
iposva@chromium.org245aa852009-02-10 00:49:54 +00007742 // If eval could not be resolved, it has been deleted and we need to
7743 // throw a reference error.
7744 if (attributes == ABSENT) {
7745 Handle<Object> name = Factory::eval_symbol();
7746 Handle<Object> reference_error =
7747 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007748 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007749 }
7750
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007751 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007752 // 'eval' is not bound in the global context. Just call the function
7753 // with the given arguments. This is not necessarily the global eval.
7754 if (receiver->IsContext()) {
7755 context = Handle<Context>::cast(receiver);
7756 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007757 } else if (receiver->IsJSContextExtensionObject()) {
7758 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007759 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007760 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007761 }
7762
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007763 // 'eval' is bound in the global context, but it may have been overwritten.
7764 // Compare it to the builtin 'GlobalEval' function to make sure.
7765 if (*callee != Top::global_context()->global_eval_fun() ||
7766 !args[1]->IsString()) {
7767 return MakePair(*callee, Top::context()->global()->global_receiver());
7768 }
7769
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007770 ASSERT(args[3]->IsSmi());
7771 return CompileGlobalEval(args.at<String>(1),
7772 args.at<Object>(2),
7773 static_cast<StrictModeFlag>(
7774 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007775}
7776
7777
7778static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007779 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007780 if (!args[0]->IsJSFunction()) {
7781 return MakePair(Top::ThrowIllegalOperation(), NULL);
7782 }
7783
7784 HandleScope scope;
7785 Handle<JSFunction> callee = args.at<JSFunction>(0);
7786
7787 // 'eval' is bound in the global context, but it may have been overwritten.
7788 // Compare it to the builtin 'GlobalEval' function to make sure.
7789 if (*callee != Top::global_context()->global_eval_fun() ||
7790 !args[1]->IsString()) {
7791 return MakePair(*callee, Top::context()->global()->global_receiver());
7792 }
7793
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007794 ASSERT(args[3]->IsSmi());
7795 return CompileGlobalEval(args.at<String>(1),
7796 args.at<Object>(2),
7797 static_cast<StrictModeFlag>(
7798 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007799}
7800
7801
lrn@chromium.org303ada72010-10-27 09:33:13 +00007802static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007803 // This utility adjusts the property attributes for newly created Function
7804 // object ("new Function(...)") by changing the map.
7805 // All it does is changing the prototype property to enumerable
7806 // as specified in ECMA262, 15.3.5.2.
7807 HandleScope scope;
7808 ASSERT(args.length() == 1);
7809 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7810 ASSERT(func->map()->instance_type() ==
7811 Top::function_instance_map()->instance_type());
7812 ASSERT(func->map()->instance_size() ==
7813 Top::function_instance_map()->instance_size());
7814 func->set_map(*Top::function_instance_map());
7815 return *func;
7816}
7817
7818
lrn@chromium.org303ada72010-10-27 09:33:13 +00007819static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007820 // Allocate a block of memory in NewSpace (filled with a filler).
7821 // Use as fallback for allocation in generated code when NewSpace
7822 // is full.
7823 ASSERT(args.length() == 1);
7824 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7825 int size = size_smi->value();
7826 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7827 RUNTIME_ASSERT(size > 0);
7828 static const int kMinFreeNewSpaceAfterGC =
7829 Heap::InitialSemiSpaceSize() * 3/4;
7830 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007831 Object* allocation;
7832 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7833 if (maybe_allocation->ToObject(&allocation)) {
7834 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7835 }
7836 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007837 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007838}
7839
7840
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007841// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007842// array. Returns true if the element was pushed on the stack and
7843// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007844static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007845 ASSERT(args.length() == 2);
7846 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007847 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007848 RUNTIME_ASSERT(array->HasFastElements());
7849 int length = Smi::cast(array->length())->value();
7850 FixedArray* elements = FixedArray::cast(array->elements());
7851 for (int i = 0; i < length; i++) {
7852 if (elements->get(i) == element) return Heap::false_value();
7853 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007854 Object* obj;
7855 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
7856 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7857 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007858 return Heap::true_value();
7859}
7860
7861
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007862/**
7863 * A simple visitor visits every element of Array's.
7864 * The backend storage can be a fixed array for fast elements case,
7865 * or a dictionary for sparse array. Since Dictionary is a subtype
7866 * of FixedArray, the class can be used by both fast and slow cases.
7867 * The second parameter of the constructor, fast_elements, specifies
7868 * whether the storage is a FixedArray or Dictionary.
7869 *
7870 * An index limit is used to deal with the situation that a result array
7871 * length overflows 32-bit non-negative integer.
7872 */
7873class ArrayConcatVisitor {
7874 public:
7875 ArrayConcatVisitor(Handle<FixedArray> storage,
7876 uint32_t index_limit,
7877 bool fast_elements) :
7878 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007879 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007880
7881 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007882 if (i >= index_limit_ - index_offset_) return;
7883 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007884
7885 if (fast_elements_) {
7886 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7887 storage_->set(index, *elm);
7888
7889 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007890 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7891 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007892 Factory::DictionaryAtNumberPut(dict, index, elm);
7893 if (!result.is_identical_to(dict))
7894 storage_ = result;
7895 }
7896 }
7897
7898 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007899 if (index_limit_ - index_offset_ < delta) {
7900 index_offset_ = index_limit_;
7901 } else {
7902 index_offset_ += delta;
7903 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007904 }
7905
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007906 Handle<FixedArray> storage() { return storage_; }
7907
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007908 private:
7909 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007910 // Limit on the accepted indices. Elements with indices larger than the
7911 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007912 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007913 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007914 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007915 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007916};
7917
7918
ager@chromium.org3811b432009-10-28 14:53:37 +00007919template<class ExternalArrayClass, class ElementType>
7920static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7921 bool elements_are_ints,
7922 bool elements_are_guaranteed_smis,
7923 uint32_t range,
7924 ArrayConcatVisitor* visitor) {
7925 Handle<ExternalArrayClass> array(
7926 ExternalArrayClass::cast(receiver->elements()));
7927 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7928
7929 if (visitor != NULL) {
7930 if (elements_are_ints) {
7931 if (elements_are_guaranteed_smis) {
7932 for (uint32_t j = 0; j < len; j++) {
7933 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7934 visitor->visit(j, e);
7935 }
7936 } else {
7937 for (uint32_t j = 0; j < len; j++) {
7938 int64_t val = static_cast<int64_t>(array->get(j));
7939 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7940 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7941 visitor->visit(j, e);
7942 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007943 Handle<Object> e =
7944 Factory::NewNumber(static_cast<ElementType>(val));
ager@chromium.org3811b432009-10-28 14:53:37 +00007945 visitor->visit(j, e);
7946 }
7947 }
7948 }
7949 } else {
7950 for (uint32_t j = 0; j < len; j++) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007951 Handle<Object> e = Factory::NewNumber(array->get(j));
ager@chromium.org3811b432009-10-28 14:53:37 +00007952 visitor->visit(j, e);
7953 }
7954 }
7955 }
7956
7957 return len;
7958}
7959
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007960/**
7961 * A helper function that visits elements of a JSObject. Only elements
7962 * whose index between 0 and range (exclusive) are visited.
7963 *
7964 * If the third parameter, visitor, is not NULL, the visitor is called
7965 * with parameters, 'visitor_index_offset + element index' and the element.
7966 *
7967 * It returns the number of visisted elements.
7968 */
7969static uint32_t IterateElements(Handle<JSObject> receiver,
7970 uint32_t range,
7971 ArrayConcatVisitor* visitor) {
7972 uint32_t num_of_elements = 0;
7973
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007974 switch (receiver->GetElementsKind()) {
7975 case JSObject::FAST_ELEMENTS: {
7976 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
7977 uint32_t len = elements->length();
7978 if (range < len) {
7979 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007980 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007981
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007982 for (uint32_t j = 0; j < len; j++) {
7983 Handle<Object> e(elements->get(j));
7984 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007985 num_of_elements++;
7986 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007987 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007988 }
7989 }
7990 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007991 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007992 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007993 case JSObject::PIXEL_ELEMENTS: {
7994 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
7995 uint32_t len = pixels->length();
7996 if (range < len) {
7997 len = range;
7998 }
7999
8000 for (uint32_t j = 0; j < len; j++) {
8001 num_of_elements++;
8002 if (visitor != NULL) {
8003 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8004 visitor->visit(j, e);
8005 }
8006 }
8007 break;
8008 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008009 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8010 num_of_elements =
8011 IterateExternalArrayElements<ExternalByteArray, int8_t>(
8012 receiver, true, true, range, visitor);
8013 break;
8014 }
8015 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8016 num_of_elements =
8017 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
8018 receiver, true, true, range, visitor);
8019 break;
8020 }
8021 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8022 num_of_elements =
8023 IterateExternalArrayElements<ExternalShortArray, int16_t>(
8024 receiver, true, true, range, visitor);
8025 break;
8026 }
8027 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8028 num_of_elements =
8029 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
8030 receiver, true, true, range, visitor);
8031 break;
8032 }
8033 case JSObject::EXTERNAL_INT_ELEMENTS: {
8034 num_of_elements =
8035 IterateExternalArrayElements<ExternalIntArray, int32_t>(
8036 receiver, true, false, range, visitor);
8037 break;
8038 }
8039 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8040 num_of_elements =
8041 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
8042 receiver, true, false, range, visitor);
8043 break;
8044 }
8045 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8046 num_of_elements =
8047 IterateExternalArrayElements<ExternalFloatArray, float>(
8048 receiver, false, false, range, visitor);
8049 break;
8050 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008051 case JSObject::DICTIONARY_ELEMENTS: {
8052 Handle<NumberDictionary> dict(receiver->element_dictionary());
8053 uint32_t capacity = dict->Capacity();
8054 for (uint32_t j = 0; j < capacity; j++) {
8055 Handle<Object> k(dict->KeyAt(j));
8056 if (dict->IsKey(*k)) {
8057 ASSERT(k->IsNumber());
8058 uint32_t index = static_cast<uint32_t>(k->Number());
8059 if (index < range) {
8060 num_of_elements++;
8061 if (visitor) {
8062 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
8063 }
8064 }
8065 }
8066 }
8067 break;
8068 }
8069 default:
8070 UNREACHABLE();
8071 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008072 }
8073
8074 return num_of_elements;
8075}
8076
8077
8078/**
8079 * A helper function that visits elements of an Array object, and elements
8080 * on its prototypes.
8081 *
8082 * Elements on prototypes are visited first, and only elements whose indices
8083 * less than Array length are visited.
8084 *
8085 * If a ArrayConcatVisitor object is given, the visitor is called with
8086 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008087 *
8088 * The returned number of elements is an upper bound on the actual number
8089 * of elements added. If the same element occurs in more than one object
8090 * in the array's prototype chain, it will be counted more than once, but
8091 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008092 */
8093static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
8094 ArrayConcatVisitor* visitor) {
8095 uint32_t range = static_cast<uint32_t>(array->length()->Number());
8096 Handle<Object> obj = array;
8097
8098 static const int kEstimatedPrototypes = 3;
8099 List< Handle<JSObject> > objects(kEstimatedPrototypes);
8100
8101 // Visit prototype first. If an element on the prototype is shadowed by
8102 // the inheritor using the same index, the ArrayConcatVisitor visits
8103 // the prototype element before the shadowing element.
8104 // The visitor can simply overwrite the old value by new value using
8105 // the same index. This follows Array::concat semantics.
8106 while (!obj->IsNull()) {
8107 objects.Add(Handle<JSObject>::cast(obj));
8108 obj = Handle<Object>(obj->GetPrototype());
8109 }
8110
8111 uint32_t nof_elements = 0;
8112 for (int i = objects.length() - 1; i >= 0; i--) {
8113 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008114 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008115 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008116
8117 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
8118 nof_elements = JSObject::kMaxElementCount;
8119 } else {
8120 nof_elements += encountered_elements;
8121 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008122 }
8123
8124 return nof_elements;
8125}
8126
8127
8128/**
8129 * A helper function of Runtime_ArrayConcat.
8130 *
8131 * The first argument is an Array of arrays and objects. It is the
8132 * same as the arguments array of Array::concat JS function.
8133 *
8134 * If an argument is an Array object, the function visits array
8135 * elements. If an argument is not an Array object, the function
8136 * visits the object as if it is an one-element array.
8137 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008138 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008139 * non-negative number is used as new length. For example, if one
8140 * array length is 2^32 - 1, second array length is 1, the
8141 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008142 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
8143 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008144 */
8145static uint32_t IterateArguments(Handle<JSArray> arguments,
8146 ArrayConcatVisitor* visitor) {
8147 uint32_t visited_elements = 0;
8148 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8149
8150 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008151 Object *element;
8152 MaybeObject* maybe_element = arguments->GetElement(i);
8153 // This if() is not expected to fail, but we have the check in the
8154 // interest of hardening the runtime calls.
8155 if (maybe_element->ToObject(&element)) {
8156 Handle<Object> obj(element);
8157 if (obj->IsJSArray()) {
8158 Handle<JSArray> array = Handle<JSArray>::cast(obj);
8159 uint32_t len = static_cast<uint32_t>(array->length()->Number());
8160 uint32_t nof_elements =
8161 IterateArrayAndPrototypeElements(array, visitor);
8162 // Total elements of array and its prototype chain can be more than
8163 // the array length, but ArrayConcat can only concatenate at most
8164 // the array length number of elements. We use the length as an estimate
8165 // for the actual number of elements added.
8166 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
8167 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
8168 visited_elements = JSArray::kMaxElementCount;
8169 } else {
8170 visited_elements += added_elements;
8171 }
8172 if (visitor) visitor->increase_index_offset(len);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008173 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008174 if (visitor) {
8175 visitor->visit(0, obj);
8176 visitor->increase_index_offset(1);
8177 }
8178 if (visited_elements < JSArray::kMaxElementCount) {
8179 visited_elements++;
8180 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008181 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008182 }
8183 }
8184 return visited_elements;
8185}
8186
8187
8188/**
8189 * Array::concat implementation.
8190 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008191 * TODO(lrn): Fix non-compliance for very large concatenations and update to
8192 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008193 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00008194static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008195 ASSERT(args.length() == 1);
8196 HandleScope handle_scope;
8197
8198 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
8199 Handle<JSArray> arguments(arg_arrays);
8200
8201 // Pass 1: estimate the number of elements of the result
8202 // (it could be more than real numbers if prototype has elements).
8203 uint32_t result_length = 0;
8204 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8205
8206 { AssertNoAllocation nogc;
8207 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008208 Object* obj;
8209 MaybeObject* maybe_object = arguments->GetElement(i);
8210 // This if() is not expected to fail, but we have the check in the
8211 // interest of hardening the runtime calls.
8212 if (maybe_object->ToObject(&obj)) {
8213 uint32_t length_estimate;
8214 if (obj->IsJSArray()) {
8215 length_estimate =
8216 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
8217 } else {
8218 length_estimate = 1;
8219 }
8220 if (JSObject::kMaxElementCount - result_length < length_estimate) {
8221 result_length = JSObject::kMaxElementCount;
8222 break;
8223 }
8224 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008225 }
8226 }
8227 }
8228
8229 // Allocate an empty array, will set length and content later.
8230 Handle<JSArray> result = Factory::NewJSArray(0);
8231
8232 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
8233 // If estimated number of elements is more than half of length, a
8234 // fixed array (fast case) is more time and space-efficient than a
8235 // dictionary.
8236 bool fast_case = (estimate_nof_elements * 2) >= result_length;
8237
8238 Handle<FixedArray> storage;
8239 if (fast_case) {
8240 // The backing storage array must have non-existing elements to
8241 // preserve holes across concat operations.
8242 storage = Factory::NewFixedArrayWithHoles(result_length);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008243 Handle<Map> fast_map =
8244 Factory::GetFastElementsMap(Handle<Map>(result->map()));
8245 result->set_map(*fast_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008246 } else {
8247 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8248 uint32_t at_least_space_for = estimate_nof_elements +
8249 (estimate_nof_elements >> 2);
8250 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008251 Factory::NewNumberDictionary(at_least_space_for));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008252 Handle<Map> slow_map =
8253 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
8254 result->set_map(*slow_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008255 }
8256
8257 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
8258
8259 ArrayConcatVisitor visitor(storage, result_length, fast_case);
8260
8261 IterateArguments(arguments, &visitor);
8262
8263 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008264 // Please note the storage might have changed in the visitor.
8265 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008266
8267 return *result;
8268}
8269
8270
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008271// This will not allocate (flatten the string), but it may run
8272// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008273static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008274 NoHandleAllocation ha;
8275 ASSERT(args.length() == 1);
8276
8277 CONVERT_CHECKED(String, string, args[0]);
8278 StringInputBuffer buffer(string);
8279 while (buffer.has_more()) {
8280 uint16_t character = buffer.GetNext();
8281 PrintF("%c", character);
8282 }
8283 return string;
8284}
8285
ager@chromium.org5ec48922009-05-05 07:25:34 +00008286// Moves all own elements of an object, that are below a limit, to positions
8287// starting at zero. All undefined values are placed after non-undefined values,
8288// and are followed by non-existing element. Does not change the length
8289// property.
8290// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008291static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008292 ASSERT(args.length() == 2);
8293 CONVERT_CHECKED(JSObject, object, args[0]);
8294 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8295 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008296}
8297
8298
8299// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00008300static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008301 ASSERT(args.length() == 2);
8302 CONVERT_CHECKED(JSArray, from, args[0]);
8303 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008304 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008305 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008306 if (new_elements->map() == Heap::fixed_array_map() ||
8307 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008308 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008309 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008310 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008311 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008312 Object* new_map;
8313 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008314 to->set_map(Map::cast(new_map));
8315 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008316 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008317 Object* obj;
8318 { MaybeObject* maybe_obj = from->ResetElements();
8319 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8320 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008321 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008322 return to;
8323}
8324
8325
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008326// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00008327static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008328 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008329 CONVERT_CHECKED(JSObject, object, args[0]);
8330 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008331 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008332 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008333 } else if (object->IsJSArray()) {
8334 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008335 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008336 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008337 }
8338}
8339
8340
lrn@chromium.org303ada72010-10-27 09:33:13 +00008341static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008342 HandleScope handle_scope;
8343
8344 ASSERT_EQ(3, args.length());
8345
ager@chromium.orgac091b72010-05-05 07:34:42 +00008346 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008347 Handle<Object> key1 = args.at<Object>(1);
8348 Handle<Object> key2 = args.at<Object>(2);
8349
8350 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008351 if (!key1->ToArrayIndex(&index1)
8352 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00008353 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008354 }
8355
ager@chromium.orgac091b72010-05-05 07:34:42 +00008356 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8357 Handle<Object> tmp1 = GetElement(jsobject, index1);
8358 Handle<Object> tmp2 = GetElement(jsobject, index2);
8359
8360 SetElement(jsobject, index1, tmp2);
8361 SetElement(jsobject, index2, tmp1);
8362
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008363 return Heap::undefined_value();
8364}
8365
8366
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008367// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008368// might have elements. Can either return keys (positive integers) or
8369// intervals (pair of a negative integer (-start-1) followed by a
8370// positive (length)) or undefined values.
8371// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008372static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008373 ASSERT(args.length() == 2);
8374 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008375 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008376 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008377 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008378 // Create an array and get all the keys into it, then remove all the
8379 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008380 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008381 int keys_length = keys->length();
8382 for (int i = 0; i < keys_length; i++) {
8383 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008384 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008385 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008386 // Zap invalid keys.
8387 keys->set_undefined(i);
8388 }
8389 }
8390 return *Factory::NewJSArrayWithElements(keys);
8391 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008392 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008393 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8394 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008395 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008396 uint32_t actual_length =
8397 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008398 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008399 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00008400 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008401 single_interval->set(1, *length_object);
8402 return *Factory::NewJSArrayWithElements(single_interval);
8403 }
8404}
8405
8406
8407// DefineAccessor takes an optional final argument which is the
8408// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8409// to the way accessors are implemented, it is set for both the getter
8410// and setter on the first call to DefineAccessor and ignored on
8411// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008412static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008413 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8414 // Compute attributes.
8415 PropertyAttributes attributes = NONE;
8416 if (args.length() == 5) {
8417 CONVERT_CHECKED(Smi, attrs, args[4]);
8418 int value = attrs->value();
8419 // Only attribute bits should be set.
8420 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8421 attributes = static_cast<PropertyAttributes>(value);
8422 }
8423
8424 CONVERT_CHECKED(JSObject, obj, args[0]);
8425 CONVERT_CHECKED(String, name, args[1]);
8426 CONVERT_CHECKED(Smi, flag, args[2]);
8427 CONVERT_CHECKED(JSFunction, fun, args[3]);
8428 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8429}
8430
8431
lrn@chromium.org303ada72010-10-27 09:33:13 +00008432static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008433 ASSERT(args.length() == 3);
8434 CONVERT_CHECKED(JSObject, obj, args[0]);
8435 CONVERT_CHECKED(String, name, args[1]);
8436 CONVERT_CHECKED(Smi, flag, args[2]);
8437 return obj->LookupAccessor(name, flag->value() == 0);
8438}
8439
8440
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008441#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00008442static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008443 ASSERT(args.length() == 0);
8444 return Execution::DebugBreakHelper();
8445}
8446
8447
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008448// Helper functions for wrapping and unwrapping stack frame ids.
8449static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008450 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008451 return Smi::FromInt(id >> 2);
8452}
8453
8454
8455static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8456 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8457}
8458
8459
8460// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00008461// args[0]: debug event listener function to set or null or undefined for
8462// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008463// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00008464static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008465 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008466 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8467 args[0]->IsUndefined() ||
8468 args[0]->IsNull());
8469 Handle<Object> callback = args.at<Object>(0);
8470 Handle<Object> data = args.at<Object>(1);
8471 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008472
8473 return Heap::undefined_value();
8474}
8475
8476
lrn@chromium.org303ada72010-10-27 09:33:13 +00008477static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008478 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008479 StackGuard::DebugBreak();
8480 return Heap::undefined_value();
8481}
8482
8483
lrn@chromium.org303ada72010-10-27 09:33:13 +00008484static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8485 LookupResult* result,
8486 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008487 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008488 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008489 case NORMAL:
8490 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008491 if (value->IsTheHole()) {
8492 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008493 }
8494 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008495 case FIELD:
8496 value =
8497 JSObject::cast(
8498 result->holder())->FastPropertyAt(result->GetFieldIndex());
8499 if (value->IsTheHole()) {
8500 return Heap::undefined_value();
8501 }
8502 return value;
8503 case CONSTANT_FUNCTION:
8504 return result->GetConstantFunction();
8505 case CALLBACKS: {
8506 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008507 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008508 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008509 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008510 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008511 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008512 ASSERT(maybe_value->IsException());
8513 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008514 Top::clear_pending_exception();
8515 if (caught_exception != NULL) {
8516 *caught_exception = true;
8517 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008518 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008519 }
8520 return value;
8521 } else {
8522 return Heap::undefined_value();
8523 }
8524 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008525 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008526 case MAP_TRANSITION:
8527 case CONSTANT_TRANSITION:
8528 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008529 return Heap::undefined_value();
8530 default:
8531 UNREACHABLE();
8532 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008533 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008534 return Heap::undefined_value();
8535}
8536
8537
ager@chromium.org32912102009-01-16 10:38:43 +00008538// Get debugger related details for an object property.
8539// args[0]: object holding property
8540// args[1]: name of the property
8541//
8542// The array returned contains the following information:
8543// 0: Property value
8544// 1: Property details
8545// 2: Property value is exception
8546// 3: Getter function if defined
8547// 4: Setter function if defined
8548// Items 2-4 are only filled if the property has either a getter or a setter
8549// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008550static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008551 HandleScope scope;
8552
8553 ASSERT(args.length() == 2);
8554
8555 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8556 CONVERT_ARG_CHECKED(String, name, 1);
8557
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008558 // Make sure to set the current context to the context before the debugger was
8559 // entered (if the debugger is entered). The reason for switching context here
8560 // is that for some property lookups (accessors and interceptors) callbacks
8561 // into the embedding application can occour, and the embedding application
8562 // could have the assumption that its own global context is the current
8563 // context and not some internal debugger context.
8564 SaveContext save;
8565 if (Debug::InDebugger()) {
8566 Top::set_context(*Debug::debugger_entry()->GetContext());
8567 }
8568
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008569 // Skip the global proxy as it has no properties and always delegates to the
8570 // real global object.
8571 if (obj->IsJSGlobalProxy()) {
8572 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8573 }
8574
8575
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008576 // Check if the name is trivially convertible to an index and get the element
8577 // if so.
8578 uint32_t index;
8579 if (name->AsArrayIndex(&index)) {
8580 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008581 Object* element_or_char;
8582 { MaybeObject* maybe_element_or_char =
8583 Runtime::GetElementOrCharAt(obj, index);
8584 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8585 return maybe_element_or_char;
8586 }
8587 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008588 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008589 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8590 return *Factory::NewJSArrayWithElements(details);
8591 }
8592
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008593 // Find the number of objects making up this.
8594 int length = LocalPrototypeChainLength(*obj);
8595
8596 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008597 Handle<JSObject> jsproto = obj;
8598 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008599 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008600 jsproto->LocalLookup(*name, &result);
8601 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008602 // LookupResult is not GC safe as it holds raw object pointers.
8603 // GC can happen later in this code so put the required fields into
8604 // local variables using handles when required for later use.
8605 PropertyType result_type = result.type();
8606 Handle<Object> result_callback_obj;
8607 if (result_type == CALLBACKS) {
8608 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8609 }
8610 Smi* property_details = result.GetPropertyDetails().AsSmi();
8611 // DebugLookupResultValue can cause GC so details from LookupResult needs
8612 // to be copied to handles before this.
8613 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008614 Object* raw_value;
8615 { MaybeObject* maybe_raw_value =
8616 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8617 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8618 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008619 Handle<Object> value(raw_value);
8620
8621 // If the callback object is a fixed array then it contains JavaScript
8622 // getter and/or setter.
8623 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8624 result_callback_obj->IsFixedArray();
8625 Handle<FixedArray> details =
8626 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8627 details->set(0, *value);
8628 details->set(1, property_details);
8629 if (hasJavaScriptAccessors) {
8630 details->set(2,
8631 caught_exception ? Heap::true_value()
8632 : Heap::false_value());
8633 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8634 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8635 }
8636
8637 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008638 }
8639 if (i < length - 1) {
8640 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8641 }
8642 }
8643
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008644 return Heap::undefined_value();
8645}
8646
8647
lrn@chromium.org303ada72010-10-27 09:33:13 +00008648static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008649 HandleScope scope;
8650
8651 ASSERT(args.length() == 2);
8652
8653 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8654 CONVERT_ARG_CHECKED(String, name, 1);
8655
8656 LookupResult result;
8657 obj->Lookup(*name, &result);
8658 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008659 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008660 }
8661 return Heap::undefined_value();
8662}
8663
8664
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008665// Return the property type calculated from the property details.
8666// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008667static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008668 ASSERT(args.length() == 1);
8669 CONVERT_CHECKED(Smi, details, args[0]);
8670 PropertyType type = PropertyDetails(details).type();
8671 return Smi::FromInt(static_cast<int>(type));
8672}
8673
8674
8675// Return the property attribute calculated from the property details.
8676// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008677static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008678 ASSERT(args.length() == 1);
8679 CONVERT_CHECKED(Smi, details, args[0]);
8680 PropertyAttributes attributes = PropertyDetails(details).attributes();
8681 return Smi::FromInt(static_cast<int>(attributes));
8682}
8683
8684
8685// Return the property insertion index calculated from the property details.
8686// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008687static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008688 ASSERT(args.length() == 1);
8689 CONVERT_CHECKED(Smi, details, args[0]);
8690 int index = PropertyDetails(details).index();
8691 return Smi::FromInt(index);
8692}
8693
8694
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008695// Return property value from named interceptor.
8696// args[0]: object
8697// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00008698static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008699 HandleScope scope;
8700 ASSERT(args.length() == 2);
8701 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8702 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8703 CONVERT_ARG_CHECKED(String, name, 1);
8704
8705 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008706 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008707}
8708
8709
8710// Return element value from indexed interceptor.
8711// args[0]: object
8712// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00008713static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8714 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008715 HandleScope scope;
8716 ASSERT(args.length() == 2);
8717 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8718 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8719 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8720
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008721 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008722}
8723
8724
lrn@chromium.org303ada72010-10-27 09:33:13 +00008725static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008726 ASSERT(args.length() >= 1);
8727 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008728 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008729 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008730 return Top::Throw(Heap::illegal_execution_state_symbol());
8731 }
8732
8733 return Heap::true_value();
8734}
8735
8736
lrn@chromium.org303ada72010-10-27 09:33:13 +00008737static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008738 HandleScope scope;
8739 ASSERT(args.length() == 1);
8740
8741 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008742 Object* result;
8743 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8744 if (!maybe_result->ToObject(&result)) return maybe_result;
8745 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008746
8747 // Count all frames which are relevant to debugging stack trace.
8748 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008749 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008750 if (id == StackFrame::NO_ID) {
8751 // If there is no JavaScript stack frame count is 0.
8752 return Smi::FromInt(0);
8753 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008754 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8755 return Smi::FromInt(n);
8756}
8757
8758
8759static const int kFrameDetailsFrameIdIndex = 0;
8760static const int kFrameDetailsReceiverIndex = 1;
8761static const int kFrameDetailsFunctionIndex = 2;
8762static const int kFrameDetailsArgumentCountIndex = 3;
8763static const int kFrameDetailsLocalCountIndex = 4;
8764static const int kFrameDetailsSourcePositionIndex = 5;
8765static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008766static const int kFrameDetailsAtReturnIndex = 7;
8767static const int kFrameDetailsDebuggerFrameIndex = 8;
8768static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008769
8770// Return an array with frame details
8771// args[0]: number: break id
8772// args[1]: number: frame index
8773//
8774// The array returned contains the following information:
8775// 0: Frame id
8776// 1: Receiver
8777// 2: Function
8778// 3: Argument count
8779// 4: Local count
8780// 5: Source position
8781// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008782// 7: Is at return
8783// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008784// Arguments name, value
8785// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008786// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00008787static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008788 HandleScope scope;
8789 ASSERT(args.length() == 2);
8790
8791 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008792 Object* check;
8793 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8794 if (!maybe_check->ToObject(&check)) return maybe_check;
8795 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008796 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8797
8798 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008799 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008800 if (id == StackFrame::NO_ID) {
8801 // If there are no JavaScript stack frames return undefined.
8802 return Heap::undefined_value();
8803 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008804 int count = 0;
8805 JavaScriptFrameIterator it(id);
8806 for (; !it.done(); it.Advance()) {
8807 if (count == index) break;
8808 count++;
8809 }
8810 if (it.done()) return Heap::undefined_value();
8811
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008812 bool is_optimized_frame =
8813 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
8814
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008815 // Traverse the saved contexts chain to find the active context for the
8816 // selected frame.
8817 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008818 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008819 save = save->prev();
8820 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008821 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008822
8823 // Get the frame id.
8824 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8825
8826 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008827 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008828
8829 // Check for constructor frame.
8830 bool constructor = it.frame()->IsConstructor();
8831
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008832 // Get scope info and read from it for local variable information.
8833 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008834 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008835 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008836
8837 // Get the context.
8838 Handle<Context> context(Context::cast(it.frame()->context()));
8839
8840 // Get the locals names and values into a temporary array.
8841 //
8842 // TODO(1240907): Hide compiler-introduced stack variables
8843 // (e.g. .result)? For users of the debugger, they will probably be
8844 // confusing.
8845 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008846
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008847 // Fill in the names of the locals.
8848 for (int i = 0; i < info.NumberOfLocals(); i++) {
8849 locals->set(i * 2, *info.LocalName(i));
8850 }
8851
8852 // Fill in the values of the locals.
8853 for (int i = 0; i < info.NumberOfLocals(); i++) {
8854 if (is_optimized_frame) {
8855 // If we are inspecting an optimized frame use undefined as the
8856 // value for all locals.
8857 //
8858 // TODO(3141533): We should be able to get the correct values
8859 // for locals in optimized frames.
8860 locals->set(i * 2 + 1, Heap::undefined_value());
8861 } else if (i < info.number_of_stack_slots()) {
8862 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008863 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8864 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008865 // Traverse the context chain to the function context as all local
8866 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008867 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008868 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008869 context = Handle<Context>(context->previous());
8870 }
8871 ASSERT(context->is_function_context());
8872 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00008873 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008874 }
8875 }
8876
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008877 // Check whether this frame is positioned at return. If not top
8878 // frame or if the frame is optimized it cannot be at a return.
8879 bool at_return = false;
8880 if (!is_optimized_frame && index == 0) {
8881 at_return = Debug::IsBreakAtReturn(it.frame());
8882 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008883
8884 // If positioned just before return find the value to be returned and add it
8885 // to the frame information.
8886 Handle<Object> return_value = Factory::undefined_value();
8887 if (at_return) {
8888 StackFrameIterator it2;
8889 Address internal_frame_sp = NULL;
8890 while (!it2.done()) {
8891 if (it2.frame()->is_internal()) {
8892 internal_frame_sp = it2.frame()->sp();
8893 } else {
8894 if (it2.frame()->is_java_script()) {
8895 if (it2.frame()->id() == it.frame()->id()) {
8896 // The internal frame just before the JavaScript frame contains the
8897 // value to return on top. A debug break at return will create an
8898 // internal frame to store the return value (eax/rax/r0) before
8899 // entering the debug break exit frame.
8900 if (internal_frame_sp != NULL) {
8901 return_value =
8902 Handle<Object>(Memory::Object_at(internal_frame_sp));
8903 break;
8904 }
8905 }
8906 }
8907
8908 // Indicate that the previous frame was not an internal frame.
8909 internal_frame_sp = NULL;
8910 }
8911 it2.Advance();
8912 }
8913 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008914
8915 // Now advance to the arguments adapter frame (if any). It contains all
8916 // the provided parameters whereas the function frame always have the number
8917 // of arguments matching the functions parameters. The rest of the
8918 // information (except for what is collected above) is the same.
8919 it.AdvanceToArgumentsFrame();
8920
8921 // Find the number of arguments to fill. At least fill the number of
8922 // parameters for the function and fill more if more parameters are provided.
8923 int argument_count = info.number_of_parameters();
8924 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8925 argument_count = it.frame()->GetProvidedParametersCount();
8926 }
8927
8928 // Calculate the size of the result.
8929 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008930 2 * (argument_count + info.NumberOfLocals()) +
8931 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008932 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8933
8934 // Add the frame id.
8935 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8936
8937 // Add the function (same as in function frame).
8938 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8939
8940 // Add the arguments count.
8941 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8942
8943 // Add the locals count
8944 details->set(kFrameDetailsLocalCountIndex,
8945 Smi::FromInt(info.NumberOfLocals()));
8946
8947 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00008948 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008949 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8950 } else {
8951 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
8952 }
8953
8954 // Add the constructor information.
8955 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
8956
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008957 // Add the at return information.
8958 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
8959
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008960 // Add information on whether this frame is invoked in the debugger context.
8961 details->set(kFrameDetailsDebuggerFrameIndex,
8962 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
8963
8964 // Fill the dynamic part.
8965 int details_index = kFrameDetailsFirstDynamicIndex;
8966
8967 // Add arguments name and value.
8968 for (int i = 0; i < argument_count; i++) {
8969 // Name of the argument.
8970 if (i < info.number_of_parameters()) {
8971 details->set(details_index++, *info.parameter_name(i));
8972 } else {
8973 details->set(details_index++, Heap::undefined_value());
8974 }
8975
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008976 // Parameter value. If we are inspecting an optimized frame, use
8977 // undefined as the value.
8978 //
8979 // TODO(3141533): We should be able to get the actual parameter
8980 // value for optimized frames.
8981 if (!is_optimized_frame &&
8982 (i < it.frame()->GetProvidedParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008983 details->set(details_index++, it.frame()->GetParameter(i));
8984 } else {
8985 details->set(details_index++, Heap::undefined_value());
8986 }
8987 }
8988
8989 // Add locals name and value from the temporary copy from the function frame.
8990 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
8991 details->set(details_index++, locals->get(i));
8992 }
8993
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008994 // Add the value being returned.
8995 if (at_return) {
8996 details->set(details_index++, *return_value);
8997 }
8998
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008999 // Add the receiver (same as in function frame).
9000 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9001 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
9002 Handle<Object> receiver(it.frame()->receiver());
9003 if (!receiver->IsJSObject()) {
9004 // If the receiver is NOT a JSObject we have hit an optimization
9005 // where a value object is not converted into a wrapped JS objects.
9006 // To hide this optimization from the debugger, we wrap the receiver
9007 // by creating correct wrapper object based on the calling frame's
9008 // global context.
9009 it.Advance();
9010 Handle<Context> calling_frames_global_context(
9011 Context::cast(Context::cast(it.frame()->context())->global_context()));
9012 receiver = Factory::ToObject(receiver, calling_frames_global_context);
9013 }
9014 details->set(kFrameDetailsReceiverIndex, *receiver);
9015
9016 ASSERT_EQ(details_size, details_index);
9017 return *Factory::NewJSArrayWithElements(details);
9018}
9019
9020
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009021// Copy all the context locals into an object used to materialize a scope.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009022static void CopyContextLocalsToScopeObject(
9023 Handle<SerializedScopeInfo> serialized_scope_info,
9024 ScopeInfo<>& scope_info,
9025 Handle<Context> context,
9026 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009027 // Fill all context locals to the context extension.
9028 for (int i = Context::MIN_CONTEXT_SLOTS;
9029 i < scope_info.number_of_context_slots();
9030 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009031 int context_index = serialized_scope_info->ContextSlotIndex(
9032 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009033
9034 // Don't include the arguments shadow (.arguments) context variable.
9035 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
9036 SetProperty(scope_object,
9037 scope_info.context_slot_name(i),
9038 Handle<Object>(context->get(context_index)), NONE);
9039 }
9040 }
9041}
9042
9043
9044// Create a plain JSObject which materializes the local scope for the specified
9045// frame.
9046static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
9047 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009048 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009049 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9050 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009051
9052 // Allocate and initialize a JSObject with all the arguments, stack locals
9053 // heap locals and extension properties of the debugged function.
9054 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
9055
9056 // First fill all parameters.
9057 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
9058 SetProperty(local_scope,
9059 scope_info.parameter_name(i),
9060 Handle<Object>(frame->GetParameter(i)), NONE);
9061 }
9062
9063 // Second fill all stack locals.
9064 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
9065 SetProperty(local_scope,
9066 scope_info.stack_slot_name(i),
9067 Handle<Object>(frame->GetExpression(i)), NONE);
9068 }
9069
9070 // Third fill all context locals.
9071 Handle<Context> frame_context(Context::cast(frame->context()));
9072 Handle<Context> function_context(frame_context->fcontext());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009073 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009074 function_context, local_scope);
9075
9076 // Finally copy any properties from the function context extension. This will
9077 // be variables introduced by eval.
9078 if (function_context->closure() == *function) {
9079 if (function_context->has_extension() &&
9080 !function_context->IsGlobalContext()) {
9081 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009082 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009083 for (int i = 0; i < keys->length(); i++) {
9084 // Names of variables introduced by eval are strings.
9085 ASSERT(keys->get(i)->IsString());
9086 Handle<String> key(String::cast(keys->get(i)));
9087 SetProperty(local_scope, key, GetProperty(ext, key), NONE);
9088 }
9089 }
9090 }
9091 return local_scope;
9092}
9093
9094
9095// Create a plain JSObject which materializes the closure content for the
9096// context.
9097static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
9098 ASSERT(context->is_function_context());
9099
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009100 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009101 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9102 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009103
9104 // Allocate and initialize a JSObject with all the content of theis function
9105 // closure.
9106 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
9107
9108 // Check whether the arguments shadow object exists.
9109 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00009110 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
9111 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009112 if (arguments_shadow_index >= 0) {
9113 // In this case all the arguments are available in the arguments shadow
9114 // object.
9115 Handle<JSObject> arguments_shadow(
9116 JSObject::cast(context->get(arguments_shadow_index)));
9117 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009118 // We don't expect exception-throwing getters on the arguments shadow.
9119 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009120 SetProperty(closure_scope,
9121 scope_info.parameter_name(i),
lrn@chromium.org303ada72010-10-27 09:33:13 +00009122 Handle<Object>(element),
9123 NONE);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009124 }
9125 }
9126
9127 // Fill all context locals to the context extension.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009128 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9129 context, closure_scope);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009130
9131 // Finally copy any properties from the function context extension. This will
9132 // be variables introduced by eval.
9133 if (context->has_extension()) {
9134 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009135 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009136 for (int i = 0; i < keys->length(); i++) {
9137 // Names of variables introduced by eval are strings.
9138 ASSERT(keys->get(i)->IsString());
9139 Handle<String> key(String::cast(keys->get(i)));
9140 SetProperty(closure_scope, key, GetProperty(ext, key), NONE);
9141 }
9142 }
9143
9144 return closure_scope;
9145}
9146
9147
9148// Iterate over the actual scopes visible from a stack frame. All scopes are
9149// backed by an actual context except the local scope, which is inserted
9150// "artifically" in the context chain.
9151class ScopeIterator {
9152 public:
9153 enum ScopeType {
9154 ScopeTypeGlobal = 0,
9155 ScopeTypeLocal,
9156 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009157 ScopeTypeClosure,
9158 // Every catch block contains an implicit with block (its parameter is
9159 // a JSContextExtensionObject) that extends current scope with a variable
9160 // holding exception object. Such with blocks are treated as scopes of their
9161 // own type.
9162 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009163 };
9164
9165 explicit ScopeIterator(JavaScriptFrame* frame)
9166 : frame_(frame),
9167 function_(JSFunction::cast(frame->function())),
9168 context_(Context::cast(frame->context())),
9169 local_done_(false),
9170 at_local_(false) {
9171
9172 // Check whether the first scope is actually a local scope.
9173 if (context_->IsGlobalContext()) {
9174 // If there is a stack slot for .result then this local scope has been
9175 // created for evaluating top level code and it is not a real local scope.
9176 // Checking for the existence of .result seems fragile, but the scope info
9177 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009178 int index = function_->shared()->scope_info()->
9179 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009180 at_local_ = index < 0;
9181 } else if (context_->is_function_context()) {
9182 at_local_ = true;
9183 }
9184 }
9185
9186 // More scopes?
9187 bool Done() { return context_.is_null(); }
9188
9189 // Move to the next scope.
9190 void Next() {
9191 // If at a local scope mark the local scope as passed.
9192 if (at_local_) {
9193 at_local_ = false;
9194 local_done_ = true;
9195
9196 // If the current context is not associated with the local scope the
9197 // current context is the next real scope, so don't move to the next
9198 // context in this case.
9199 if (context_->closure() != *function_) {
9200 return;
9201 }
9202 }
9203
9204 // The global scope is always the last in the chain.
9205 if (context_->IsGlobalContext()) {
9206 context_ = Handle<Context>();
9207 return;
9208 }
9209
9210 // Move to the next context.
9211 if (context_->is_function_context()) {
9212 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9213 } else {
9214 context_ = Handle<Context>(context_->previous());
9215 }
9216
9217 // If passing the local scope indicate that the current scope is now the
9218 // local scope.
9219 if (!local_done_ &&
9220 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9221 at_local_ = true;
9222 }
9223 }
9224
9225 // Return the type of the current scope.
9226 int Type() {
9227 if (at_local_) {
9228 return ScopeTypeLocal;
9229 }
9230 if (context_->IsGlobalContext()) {
9231 ASSERT(context_->global()->IsGlobalObject());
9232 return ScopeTypeGlobal;
9233 }
9234 if (context_->is_function_context()) {
9235 return ScopeTypeClosure;
9236 }
9237 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009238 // Current scope is either an explicit with statement or a with statement
9239 // implicitely generated for a catch block.
9240 // If the extension object here is a JSContextExtensionObject then
9241 // current with statement is one frome a catch block otherwise it's a
9242 // regular with statement.
9243 if (context_->extension()->IsJSContextExtensionObject()) {
9244 return ScopeTypeCatch;
9245 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009246 return ScopeTypeWith;
9247 }
9248
9249 // Return the JavaScript object with the content of the current scope.
9250 Handle<JSObject> ScopeObject() {
9251 switch (Type()) {
9252 case ScopeIterator::ScopeTypeGlobal:
9253 return Handle<JSObject>(CurrentContext()->global());
9254 break;
9255 case ScopeIterator::ScopeTypeLocal:
9256 // Materialize the content of the local scope into a JSObject.
9257 return MaterializeLocalScope(frame_);
9258 break;
9259 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009260 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009261 // Return the with object.
9262 return Handle<JSObject>(CurrentContext()->extension());
9263 break;
9264 case ScopeIterator::ScopeTypeClosure:
9265 // Materialize the content of the closure scope into a JSObject.
9266 return MaterializeClosure(CurrentContext());
9267 break;
9268 }
9269 UNREACHABLE();
9270 return Handle<JSObject>();
9271 }
9272
9273 // Return the context for this scope. For the local context there might not
9274 // be an actual context.
9275 Handle<Context> CurrentContext() {
9276 if (at_local_ && context_->closure() != *function_) {
9277 return Handle<Context>();
9278 }
9279 return context_;
9280 }
9281
9282#ifdef DEBUG
9283 // Debug print of the content of the current scope.
9284 void DebugPrint() {
9285 switch (Type()) {
9286 case ScopeIterator::ScopeTypeGlobal:
9287 PrintF("Global:\n");
9288 CurrentContext()->Print();
9289 break;
9290
9291 case ScopeIterator::ScopeTypeLocal: {
9292 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009293 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009294 scope_info.Print();
9295 if (!CurrentContext().is_null()) {
9296 CurrentContext()->Print();
9297 if (CurrentContext()->has_extension()) {
9298 Handle<JSObject> extension =
9299 Handle<JSObject>(CurrentContext()->extension());
9300 if (extension->IsJSContextExtensionObject()) {
9301 extension->Print();
9302 }
9303 }
9304 }
9305 break;
9306 }
9307
9308 case ScopeIterator::ScopeTypeWith: {
9309 PrintF("With:\n");
9310 Handle<JSObject> extension =
9311 Handle<JSObject>(CurrentContext()->extension());
9312 extension->Print();
9313 break;
9314 }
9315
ager@chromium.orga1645e22009-09-09 19:27:10 +00009316 case ScopeIterator::ScopeTypeCatch: {
9317 PrintF("Catch:\n");
9318 Handle<JSObject> extension =
9319 Handle<JSObject>(CurrentContext()->extension());
9320 extension->Print();
9321 break;
9322 }
9323
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009324 case ScopeIterator::ScopeTypeClosure: {
9325 PrintF("Closure:\n");
9326 CurrentContext()->Print();
9327 if (CurrentContext()->has_extension()) {
9328 Handle<JSObject> extension =
9329 Handle<JSObject>(CurrentContext()->extension());
9330 if (extension->IsJSContextExtensionObject()) {
9331 extension->Print();
9332 }
9333 }
9334 break;
9335 }
9336
9337 default:
9338 UNREACHABLE();
9339 }
9340 PrintF("\n");
9341 }
9342#endif
9343
9344 private:
9345 JavaScriptFrame* frame_;
9346 Handle<JSFunction> function_;
9347 Handle<Context> context_;
9348 bool local_done_;
9349 bool at_local_;
9350
9351 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9352};
9353
9354
lrn@chromium.org303ada72010-10-27 09:33:13 +00009355static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009356 HandleScope scope;
9357 ASSERT(args.length() == 2);
9358
9359 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009360 Object* check;
9361 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9362 if (!maybe_check->ToObject(&check)) return maybe_check;
9363 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009364 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9365
9366 // Get the frame where the debugging is performed.
9367 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9368 JavaScriptFrameIterator it(id);
9369 JavaScriptFrame* frame = it.frame();
9370
9371 // Count the visible scopes.
9372 int n = 0;
9373 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9374 n++;
9375 }
9376
9377 return Smi::FromInt(n);
9378}
9379
9380
9381static const int kScopeDetailsTypeIndex = 0;
9382static const int kScopeDetailsObjectIndex = 1;
9383static const int kScopeDetailsSize = 2;
9384
9385// Return an array with scope details
9386// args[0]: number: break id
9387// args[1]: number: frame index
9388// args[2]: number: scope index
9389//
9390// The array returned contains the following information:
9391// 0: Scope type
9392// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009393static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009394 HandleScope scope;
9395 ASSERT(args.length() == 3);
9396
9397 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009398 Object* check;
9399 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9400 if (!maybe_check->ToObject(&check)) return maybe_check;
9401 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009402 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9403 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9404
9405 // Get the frame where the debugging is performed.
9406 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9407 JavaScriptFrameIterator frame_it(id);
9408 JavaScriptFrame* frame = frame_it.frame();
9409
9410 // Find the requested scope.
9411 int n = 0;
9412 ScopeIterator it(frame);
9413 for (; !it.Done() && n < index; it.Next()) {
9414 n++;
9415 }
9416 if (it.Done()) {
9417 return Heap::undefined_value();
9418 }
9419
9420 // Calculate the size of the result.
9421 int details_size = kScopeDetailsSize;
9422 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9423
9424 // Fill in scope details.
9425 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009426 Handle<JSObject> scope_object = it.ScopeObject();
9427 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009428
9429 return *Factory::NewJSArrayWithElements(details);
9430}
9431
9432
lrn@chromium.org303ada72010-10-27 09:33:13 +00009433static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009434 HandleScope scope;
9435 ASSERT(args.length() == 0);
9436
9437#ifdef DEBUG
9438 // Print the scopes for the top frame.
9439 StackFrameLocator locator;
9440 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9441 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9442 it.DebugPrint();
9443 }
9444#endif
9445 return Heap::undefined_value();
9446}
9447
9448
lrn@chromium.org303ada72010-10-27 09:33:13 +00009449static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009450 HandleScope scope;
9451 ASSERT(args.length() == 1);
9452
9453 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009454 Object* result;
9455 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9456 if (!maybe_result->ToObject(&result)) return maybe_result;
9457 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009458
9459 // Count all archived V8 threads.
9460 int n = 0;
9461 for (ThreadState* thread = ThreadState::FirstInUse();
9462 thread != NULL;
9463 thread = thread->Next()) {
9464 n++;
9465 }
9466
9467 // Total number of threads is current thread and archived threads.
9468 return Smi::FromInt(n + 1);
9469}
9470
9471
9472static const int kThreadDetailsCurrentThreadIndex = 0;
9473static const int kThreadDetailsThreadIdIndex = 1;
9474static const int kThreadDetailsSize = 2;
9475
9476// Return an array with thread details
9477// args[0]: number: break id
9478// args[1]: number: thread index
9479//
9480// The array returned contains the following information:
9481// 0: Is current thread?
9482// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00009483static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009484 HandleScope scope;
9485 ASSERT(args.length() == 2);
9486
9487 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009488 Object* check;
9489 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9490 if (!maybe_check->ToObject(&check)) return maybe_check;
9491 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009492 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9493
9494 // Allocate array for result.
9495 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9496
9497 // Thread index 0 is current thread.
9498 if (index == 0) {
9499 // Fill the details.
9500 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9501 details->set(kThreadDetailsThreadIdIndex,
9502 Smi::FromInt(ThreadManager::CurrentId()));
9503 } else {
9504 // Find the thread with the requested index.
9505 int n = 1;
9506 ThreadState* thread = ThreadState::FirstInUse();
9507 while (index != n && thread != NULL) {
9508 thread = thread->Next();
9509 n++;
9510 }
9511 if (thread == NULL) {
9512 return Heap::undefined_value();
9513 }
9514
9515 // Fill the details.
9516 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9517 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9518 }
9519
9520 // Convert to JS array and return.
9521 return *Factory::NewJSArrayWithElements(details);
9522}
9523
9524
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009525// Sets the disable break state
9526// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00009527static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009528 HandleScope scope;
9529 ASSERT(args.length() == 1);
9530 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9531 Debug::set_disable_break(disable_break);
9532 return Heap::undefined_value();
9533}
9534
9535
lrn@chromium.org303ada72010-10-27 09:33:13 +00009536static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009537 HandleScope scope;
9538 ASSERT(args.length() == 1);
9539
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009540 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9541 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009542 // Find the number of break points
9543 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9544 if (break_locations->IsUndefined()) return Heap::undefined_value();
9545 // Return array as JS array
9546 return *Factory::NewJSArrayWithElements(
9547 Handle<FixedArray>::cast(break_locations));
9548}
9549
9550
9551// Set a break point in a function
9552// args[0]: function
9553// args[1]: number: break source position (within the function source)
9554// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009555static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009556 HandleScope scope;
9557 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009558 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9559 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009560 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9561 RUNTIME_ASSERT(source_position >= 0);
9562 Handle<Object> break_point_object_arg = args.at<Object>(2);
9563
9564 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009565 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009566
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009567 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009568}
9569
9570
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009571Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9572 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009573 // Iterate the heap looking for SharedFunctionInfo generated from the
9574 // script. The inner most SharedFunctionInfo containing the source position
9575 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009576 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009577 // which is found is not compiled it is compiled and the heap is iterated
9578 // again as the compilation might create inner functions from the newly
9579 // compiled function and the actual requested break point might be in one of
9580 // these functions.
9581 bool done = false;
9582 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009583 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009584 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009585 while (!done) {
9586 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009587 for (HeapObject* obj = iterator.next();
9588 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009589 if (obj->IsSharedFunctionInfo()) {
9590 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9591 if (shared->script() == *script) {
9592 // If the SharedFunctionInfo found has the requested script data and
9593 // contains the source position it is a candidate.
9594 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009595 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009596 start_position = shared->start_position();
9597 }
9598 if (start_position <= position &&
9599 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009600 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009601 // candidate this is the new candidate.
9602 if (target.is_null()) {
9603 target_start_position = start_position;
9604 target = shared;
9605 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009606 if (target_start_position == start_position &&
9607 shared->end_position() == target->end_position()) {
9608 // If a top-level function contain only one function
9609 // declartion the source for the top-level and the function is
9610 // the same. In that case prefer the non top-level function.
9611 if (!shared->is_toplevel()) {
9612 target_start_position = start_position;
9613 target = shared;
9614 }
9615 } else if (target_start_position <= start_position &&
9616 shared->end_position() <= target->end_position()) {
9617 // This containment check includes equality as a function inside
9618 // a top-level function can share either start or end position
9619 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009620 target_start_position = start_position;
9621 target = shared;
9622 }
9623 }
9624 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009625 }
9626 }
9627 }
9628
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009629 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009630 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009631 }
9632
9633 // If the candidate found is compiled we are done. NOTE: when lazy
9634 // compilation of inner functions is introduced some additional checking
9635 // needs to be done here to compile inner functions.
9636 done = target->is_compiled();
9637 if (!done) {
9638 // If the candidate is not compiled compile it to reveal any inner
9639 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009640 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009641 }
9642 }
9643
9644 return *target;
9645}
9646
9647
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009648// Changes the state of a break point in a script and returns source position
9649// where break point was set. NOTE: Regarding performance see the NOTE for
9650// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009651// args[0]: script to set break point in
9652// args[1]: number: break source position (within the script source)
9653// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009654static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009655 HandleScope scope;
9656 ASSERT(args.length() == 3);
9657 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9658 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9659 RUNTIME_ASSERT(source_position >= 0);
9660 Handle<Object> break_point_object_arg = args.at<Object>(2);
9661
9662 // Get the script from the script wrapper.
9663 RUNTIME_ASSERT(wrapper->value()->IsScript());
9664 Handle<Script> script(Script::cast(wrapper->value()));
9665
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009666 Object* result = Runtime::FindSharedFunctionInfoInScript(
9667 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009668 if (!result->IsUndefined()) {
9669 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9670 // Find position within function. The script position might be before the
9671 // source position of the first function.
9672 int position;
9673 if (shared->start_position() > source_position) {
9674 position = 0;
9675 } else {
9676 position = source_position - shared->start_position();
9677 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009678 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9679 position += shared->start_position();
9680 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009681 }
9682 return Heap::undefined_value();
9683}
9684
9685
9686// Clear a break point
9687// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009688static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009689 HandleScope scope;
9690 ASSERT(args.length() == 1);
9691 Handle<Object> break_point_object_arg = args.at<Object>(0);
9692
9693 // Clear break point.
9694 Debug::ClearBreakPoint(break_point_object_arg);
9695
9696 return Heap::undefined_value();
9697}
9698
9699
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009700// Change the state of break on exceptions.
9701// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9702// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009703static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009704 HandleScope scope;
9705 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009706 RUNTIME_ASSERT(args[0]->IsNumber());
9707 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009708
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009709 // If the number doesn't match an enum value, the ChangeBreakOnException
9710 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009711 ExceptionBreakType type =
9712 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009713 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009714 Debug::ChangeBreakOnException(type, enable);
9715 return Heap::undefined_value();
9716}
9717
9718
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009719// Returns the state of break on exceptions
9720// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +00009721static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009722 HandleScope scope;
9723 ASSERT(args.length() == 1);
9724 RUNTIME_ASSERT(args[0]->IsNumber());
9725
9726 ExceptionBreakType type =
9727 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9728 bool result = Debug::IsBreakOnException(type);
9729 return Smi::FromInt(result);
9730}
9731
9732
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009733// Prepare for stepping
9734// args[0]: break id for checking execution state
9735// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009736// args[2]: number of times to perform the step, for step out it is the number
9737// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009738static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009739 HandleScope scope;
9740 ASSERT(args.length() == 3);
9741 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009742 Object* check;
9743 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9744 if (!maybe_check->ToObject(&check)) return maybe_check;
9745 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009746 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9747 return Top::Throw(Heap::illegal_argument_symbol());
9748 }
9749
9750 // Get the step action and check validity.
9751 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9752 if (step_action != StepIn &&
9753 step_action != StepNext &&
9754 step_action != StepOut &&
9755 step_action != StepInMin &&
9756 step_action != StepMin) {
9757 return Top::Throw(Heap::illegal_argument_symbol());
9758 }
9759
9760 // Get the number of steps.
9761 int step_count = NumberToInt32(args[2]);
9762 if (step_count < 1) {
9763 return Top::Throw(Heap::illegal_argument_symbol());
9764 }
9765
ager@chromium.orga1645e22009-09-09 19:27:10 +00009766 // Clear all current stepping setup.
9767 Debug::ClearStepping();
9768
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009769 // Prepare step.
9770 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9771 return Heap::undefined_value();
9772}
9773
9774
9775// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009776static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009777 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009778 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009779 Debug::ClearStepping();
9780 return Heap::undefined_value();
9781}
9782
9783
9784// Creates a copy of the with context chain. The copy of the context chain is
9785// is linked to the function context supplied.
9786static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9787 Handle<Context> function_context) {
9788 // At the bottom of the chain. Return the function context to link to.
9789 if (context_chain->is_function_context()) {
9790 return function_context;
9791 }
9792
9793 // Recursively copy the with contexts.
9794 Handle<Context> previous(context_chain->previous());
9795 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009796 Handle<Context> context = CopyWithContextChain(function_context, previous);
9797 return Factory::NewWithContext(context,
9798 extension,
9799 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009800}
9801
9802
9803// Helper function to find or create the arguments object for
9804// Runtime_DebugEvaluate.
9805static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9806 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009807 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009808 const ScopeInfo<>* sinfo,
9809 Handle<Context> function_context) {
9810 // Try to find the value of 'arguments' to pass as parameter. If it is not
9811 // found (that is the debugged function does not reference 'arguments' and
9812 // does not support eval) then create an 'arguments' object.
9813 int index;
9814 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009815 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009816 if (index != -1) {
9817 return Handle<Object>(frame->GetExpression(index));
9818 }
9819 }
9820
9821 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009822 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009823 if (index != -1) {
9824 return Handle<Object>(function_context->get(index));
9825 }
9826 }
9827
9828 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009829 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9830 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009831
9832 AssertNoAllocation no_gc;
9833 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009834 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009835 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009836 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009837 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009838 return arguments;
9839}
9840
9841
9842// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009843// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009844// extension part has all the parameters and locals of the function on the
9845// stack frame. A function which calls eval with the code to evaluate is then
9846// compiled in this context and called in this context. As this context
9847// replaces the context of the function on the stack frame a new (empty)
9848// function is created as well to be used as the closure for the context.
9849// This function and the context acts as replacements for the function on the
9850// stack frame presenting the same view of the values of parameters and
9851// local variables as if the piece of JavaScript was evaluated at the point
9852// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009853static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009854 HandleScope scope;
9855
9856 // Check the execution state and decode arguments frame and source to be
9857 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009858 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009859 Object* check_result;
9860 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9861 if (!maybe_check_result->ToObject(&check_result)) {
9862 return maybe_check_result;
9863 }
9864 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009865 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9866 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009867 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009868 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009869
9870 // Handle the processing of break.
9871 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009872
9873 // Get the frame where the debugging is performed.
9874 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9875 JavaScriptFrameIterator it(id);
9876 JavaScriptFrame* frame = it.frame();
9877 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009878 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009879 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009880
9881 // Traverse the saved contexts chain to find the active context for the
9882 // selected frame.
9883 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009884 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009885 save = save->prev();
9886 }
9887 ASSERT(save != NULL);
9888 SaveContext savex;
9889 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009890
9891 // Create the (empty) function replacing the function on the stack frame for
9892 // the purpose of evaluating in the context created below. It is important
9893 // that this function does not describe any parameters and local variables
9894 // in the context. If it does then this will cause problems with the lookup
9895 // in Context::Lookup, where context slots for parameters and local variables
9896 // are looked at before the extension object.
9897 Handle<JSFunction> go_between =
9898 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9899 go_between->set_context(function->context());
9900#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009901 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009902 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9903 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9904#endif
9905
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009906 // Materialize the content of the local scope into a JSObject.
9907 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009908
9909 // Allocate a new context for the debug evaluation and set the extension
9910 // object build.
9911 Handle<Context> context =
9912 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009913 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009914 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009915 Handle<Context> frame_context(Context::cast(frame->context()));
9916 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009917 context = CopyWithContextChain(frame_context, context);
9918
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009919 if (additional_context->IsJSObject()) {
9920 context = Factory::NewWithContext(context,
9921 Handle<JSObject>::cast(additional_context), false);
9922 }
9923
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009924 // Wrap the evaluation statement in a new function compiled in the newly
9925 // created context. The function has one parameter which has to be called
9926 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00009927 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009928 // function(arguments,__source__) {return eval(__source__);}
9929 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009930 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009931 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009932 Handle<String> function_source =
9933 Factory::NewStringFromAscii(Vector<const char>(source_str,
9934 source_str_length));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009935
9936 // Currently, the eval code will be executed in non-strict mode,
9937 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009938 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +00009939 Compiler::CompileEval(function_source,
9940 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009941 context->IsGlobalContext(),
9942 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009943 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009944 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009945 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009946
9947 // Invoke the result of the compilation to get the evaluation function.
9948 bool has_pending_exception;
9949 Handle<Object> receiver(frame->receiver());
9950 Handle<Object> evaluation_function =
9951 Execution::Call(compiled_function, receiver, 0, NULL,
9952 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009953 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009954
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009955 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
9956 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009957
9958 // Invoke the evaluation function and return the result.
9959 const int argc = 2;
9960 Object** argv[argc] = { arguments.location(),
9961 Handle<Object>::cast(source).location() };
9962 Handle<Object> result =
9963 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
9964 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009965 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009966
9967 // Skip the global proxy as it has no properties and always delegates to the
9968 // real global object.
9969 if (result->IsJSGlobalProxy()) {
9970 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
9971 }
9972
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009973 return *result;
9974}
9975
9976
lrn@chromium.org303ada72010-10-27 09:33:13 +00009977static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009978 HandleScope scope;
9979
9980 // Check the execution state and decode arguments frame and source to be
9981 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009982 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009983 Object* check_result;
9984 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9985 if (!maybe_check_result->ToObject(&check_result)) {
9986 return maybe_check_result;
9987 }
9988 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009989 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009990 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009991 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009992
9993 // Handle the processing of break.
9994 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009995
9996 // Enter the top context from before the debugger was invoked.
9997 SaveContext save;
9998 SaveContext* top = &save;
9999 while (top != NULL && *top->context() == *Debug::debug_context()) {
10000 top = top->prev();
10001 }
10002 if (top != NULL) {
10003 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010004 }
10005
10006 // Get the global context now set to the top context from before the
10007 // debugger was invoked.
10008 Handle<Context> context = Top::global_context();
10009
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010010 bool is_global = true;
10011
10012 if (additional_context->IsJSObject()) {
10013 // Create a function context first, than put 'with' context on top of it.
10014 Handle<JSFunction> go_between = Factory::NewFunction(
10015 Factory::empty_string(), Factory::undefined_value());
10016 go_between->set_context(*context);
10017 context =
10018 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
10019 context->set_extension(JSObject::cast(*additional_context));
10020 is_global = false;
10021 }
10022
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010023 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010024 // Currently, the eval code will be executed in non-strict mode,
10025 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010026 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010027 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010028 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010029 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010030 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
10031 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010032
10033 // Invoke the result of the compilation to get the evaluation function.
10034 bool has_pending_exception;
10035 Handle<Object> receiver = Top::global();
10036 Handle<Object> result =
10037 Execution::Call(compiled_function, receiver, 0, NULL,
10038 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010039 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010040 return *result;
10041}
10042
10043
lrn@chromium.org303ada72010-10-27 09:33:13 +000010044static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010045 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +000010046 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010047
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010048 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010049 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010050
10051 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010052 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010053 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10054 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10055 // because using
10056 // instances->set(i, *GetScriptWrapper(script))
10057 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10058 // already have deferenced the instances handle.
10059 Handle<JSValue> wrapper = GetScriptWrapper(script);
10060 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010061 }
10062
10063 // Return result as a JS array.
10064 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
10065 Handle<JSArray>::cast(result)->SetContent(*instances);
10066 return *result;
10067}
10068
10069
10070// Helper function used by Runtime_DebugReferencedBy below.
10071static int DebugReferencedBy(JSObject* target,
10072 Object* instance_filter, int max_references,
10073 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010074 JSFunction* arguments_function) {
10075 NoHandleAllocation ha;
10076 AssertNoAllocation no_alloc;
10077
10078 // Iterate the heap.
10079 int count = 0;
10080 JSObject* last = NULL;
10081 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010082 HeapObject* heap_obj = NULL;
10083 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010084 (max_references == 0 || count < max_references)) {
10085 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010086 if (heap_obj->IsJSObject()) {
10087 // Skip context extension objects and argument arrays as these are
10088 // checked in the context of functions using them.
10089 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010090 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010091 obj->map()->constructor() == arguments_function) {
10092 continue;
10093 }
10094
10095 // Check if the JS object has a reference to the object looked for.
10096 if (obj->ReferencesObject(target)) {
10097 // Check instance filter if supplied. This is normally used to avoid
10098 // references from mirror objects (see Runtime_IsInPrototypeChain).
10099 if (!instance_filter->IsUndefined()) {
10100 Object* V = obj;
10101 while (true) {
10102 Object* prototype = V->GetPrototype();
10103 if (prototype->IsNull()) {
10104 break;
10105 }
10106 if (instance_filter == prototype) {
10107 obj = NULL; // Don't add this object.
10108 break;
10109 }
10110 V = prototype;
10111 }
10112 }
10113
10114 if (obj != NULL) {
10115 // Valid reference found add to instance array if supplied an update
10116 // count.
10117 if (instances != NULL && count < instances_size) {
10118 instances->set(count, obj);
10119 }
10120 last = obj;
10121 count++;
10122 }
10123 }
10124 }
10125 }
10126
10127 // Check for circular reference only. This can happen when the object is only
10128 // referenced from mirrors and has a circular reference in which case the
10129 // object is not really alive and would have been garbage collected if not
10130 // referenced from the mirror.
10131 if (count == 1 && last == target) {
10132 count = 0;
10133 }
10134
10135 // Return the number of referencing objects found.
10136 return count;
10137}
10138
10139
10140// Scan the heap for objects with direct references to an object
10141// args[0]: the object to find references to
10142// args[1]: constructor function for instances to exclude (Mirror)
10143// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010144static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010145 ASSERT(args.length() == 3);
10146
10147 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010148 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010149
10150 // Check parameters.
10151 CONVERT_CHECKED(JSObject, target, args[0]);
10152 Object* instance_filter = args[1];
10153 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10154 instance_filter->IsJSObject());
10155 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10156 RUNTIME_ASSERT(max_references >= 0);
10157
10158 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010159 JSObject* arguments_boilerplate =
10160 Top::context()->global_context()->arguments_boilerplate();
10161 JSFunction* arguments_function =
10162 JSFunction::cast(arguments_boilerplate->map()->constructor());
10163
10164 // Get the number of referencing objects.
10165 int count;
10166 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010167 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010168
10169 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010170 Object* object;
10171 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10172 if (!maybe_object->ToObject(&object)) return maybe_object;
10173 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010174 FixedArray* instances = FixedArray::cast(object);
10175
10176 // Fill the referencing objects.
10177 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010178 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010179
10180 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010181 Object* result;
10182 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10183 Top::context()->global_context()->array_function());
10184 if (!maybe_result->ToObject(&result)) return maybe_result;
10185 }
10186 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010187 return result;
10188}
10189
10190
10191// Helper function used by Runtime_DebugConstructedBy below.
10192static int DebugConstructedBy(JSFunction* constructor, int max_references,
10193 FixedArray* instances, int instances_size) {
10194 AssertNoAllocation no_alloc;
10195
10196 // Iterate the heap.
10197 int count = 0;
10198 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010199 HeapObject* heap_obj = NULL;
10200 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010201 (max_references == 0 || count < max_references)) {
10202 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010203 if (heap_obj->IsJSObject()) {
10204 JSObject* obj = JSObject::cast(heap_obj);
10205 if (obj->map()->constructor() == constructor) {
10206 // Valid reference found add to instance array if supplied an update
10207 // count.
10208 if (instances != NULL && count < instances_size) {
10209 instances->set(count, obj);
10210 }
10211 count++;
10212 }
10213 }
10214 }
10215
10216 // Return the number of referencing objects found.
10217 return count;
10218}
10219
10220
10221// Scan the heap for objects constructed by a specific function.
10222// args[0]: the constructor to find instances of
10223// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010224static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010225 ASSERT(args.length() == 2);
10226
10227 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010228 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010229
10230 // Check parameters.
10231 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10232 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10233 RUNTIME_ASSERT(max_references >= 0);
10234
10235 // Get the number of referencing objects.
10236 int count;
10237 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10238
10239 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010240 Object* object;
10241 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10242 if (!maybe_object->ToObject(&object)) return maybe_object;
10243 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010244 FixedArray* instances = FixedArray::cast(object);
10245
10246 // Fill the referencing objects.
10247 count = DebugConstructedBy(constructor, max_references, instances, count);
10248
10249 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010250 Object* result;
10251 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10252 Top::context()->global_context()->array_function());
10253 if (!maybe_result->ToObject(&result)) return maybe_result;
10254 }
10255 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010256 return result;
10257}
10258
10259
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010260// Find the effective prototype object as returned by __proto__.
10261// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010262static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010263 ASSERT(args.length() == 1);
10264
10265 CONVERT_CHECKED(JSObject, obj, args[0]);
10266
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010267 // Use the __proto__ accessor.
10268 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010269}
10270
10271
lrn@chromium.org303ada72010-10-27 09:33:13 +000010272static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010273 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010274 CPU::DebugBreak();
10275 return Heap::undefined_value();
10276}
10277
10278
lrn@chromium.org303ada72010-10-27 09:33:13 +000010279static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010280#ifdef DEBUG
10281 HandleScope scope;
10282 ASSERT(args.length() == 1);
10283 // Get the function and make sure it is compiled.
10284 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010285 Handle<SharedFunctionInfo> shared(func->shared());
10286 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010287 return Failure::Exception();
10288 }
10289 func->code()->PrintLn();
10290#endif // DEBUG
10291 return Heap::undefined_value();
10292}
ager@chromium.org9085a012009-05-11 19:22:57 +000010293
10294
lrn@chromium.org303ada72010-10-27 09:33:13 +000010295static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010296#ifdef DEBUG
10297 HandleScope scope;
10298 ASSERT(args.length() == 1);
10299 // Get the function and make sure it is compiled.
10300 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010301 Handle<SharedFunctionInfo> shared(func->shared());
10302 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010303 return Failure::Exception();
10304 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010305 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010306#endif // DEBUG
10307 return Heap::undefined_value();
10308}
10309
10310
lrn@chromium.org303ada72010-10-27 09:33:13 +000010311static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010312 NoHandleAllocation ha;
10313 ASSERT(args.length() == 1);
10314
10315 CONVERT_CHECKED(JSFunction, f, args[0]);
10316 return f->shared()->inferred_name();
10317}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010318
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010319
10320static int FindSharedFunctionInfosForScript(Script* script,
10321 FixedArray* buffer) {
10322 AssertNoAllocation no_allocations;
10323
10324 int counter = 0;
10325 int buffer_size = buffer->length();
10326 HeapIterator iterator;
10327 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10328 ASSERT(obj != NULL);
10329 if (!obj->IsSharedFunctionInfo()) {
10330 continue;
10331 }
10332 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10333 if (shared->script() != script) {
10334 continue;
10335 }
10336 if (counter < buffer_size) {
10337 buffer->set(counter, shared);
10338 }
10339 counter++;
10340 }
10341 return counter;
10342}
10343
10344// For a script finds all SharedFunctionInfo's in the heap that points
10345// to this script. Returns JSArray of SharedFunctionInfo wrapped
10346// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010347static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010348 Arguments args) {
10349 ASSERT(args.length() == 1);
10350 HandleScope scope;
10351 CONVERT_CHECKED(JSValue, script_value, args[0]);
10352
10353 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10354
10355 const int kBufferSize = 32;
10356
10357 Handle<FixedArray> array;
10358 array = Factory::NewFixedArray(kBufferSize);
10359 int number = FindSharedFunctionInfosForScript(*script, *array);
10360 if (number > kBufferSize) {
10361 array = Factory::NewFixedArray(number);
10362 FindSharedFunctionInfosForScript(*script, *array);
10363 }
10364
10365 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10366 result->set_length(Smi::FromInt(number));
10367
10368 LiveEdit::WrapSharedFunctionInfos(result);
10369
10370 return *result;
10371}
10372
10373// For a script calculates compilation information about all its functions.
10374// The script source is explicitly specified by the second argument.
10375// The source of the actual script is not used, however it is important that
10376// all generated code keeps references to this particular instance of script.
10377// Returns a JSArray of compilation infos. The array is ordered so that
10378// each function with all its descendant is always stored in a continues range
10379// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010380static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010381 ASSERT(args.length() == 2);
10382 HandleScope scope;
10383 CONVERT_CHECKED(JSValue, script, args[0]);
10384 CONVERT_ARG_CHECKED(String, source, 1);
10385 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10386
10387 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10388
10389 if (Top::has_pending_exception()) {
10390 return Failure::Exception();
10391 }
10392
10393 return result;
10394}
10395
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010396// Changes the source of the script to a new_source.
10397// If old_script_name is provided (i.e. is a String), also creates a copy of
10398// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010399static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010400 ASSERT(args.length() == 3);
10401 HandleScope scope;
10402 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10403 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010404 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010405
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010406 CONVERT_CHECKED(Script, original_script_pointer,
10407 original_script_value->value());
10408 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010409
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010410 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10411 new_source,
10412 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010413
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010414 if (old_script->IsScript()) {
10415 Handle<Script> script_handle(Script::cast(old_script));
10416 return *(GetScriptWrapper(script_handle));
10417 } else {
10418 return Heap::null_value();
10419 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010420}
10421
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010422
10423static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10424 ASSERT(args.length() == 1);
10425 HandleScope scope;
10426 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10427 return LiveEdit::FunctionSourceUpdated(shared_info);
10428}
10429
10430
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010431// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010432static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010433 ASSERT(args.length() == 2);
10434 HandleScope scope;
10435 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10436 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10437
ager@chromium.orgac091b72010-05-05 07:34:42 +000010438 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010439}
10440
10441// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010442static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010443 ASSERT(args.length() == 2);
10444 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010445 Handle<Object> function_object(args[0]);
10446 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010447
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010448 if (function_object->IsJSValue()) {
10449 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10450 if (script_object->IsJSValue()) {
10451 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10452 script_object = Handle<Object>(script);
10453 }
10454
10455 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10456 } else {
10457 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10458 // and we check it in this function.
10459 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010460
10461 return Heap::undefined_value();
10462}
10463
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010464
10465// In a code of a parent function replaces original function as embedded object
10466// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010467static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010468 ASSERT(args.length() == 3);
10469 HandleScope scope;
10470
10471 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10472 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10473 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10474
10475 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10476 subst_wrapper);
10477
10478 return Heap::undefined_value();
10479}
10480
10481
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010482// Updates positions of a shared function info (first parameter) according
10483// to script source change. Text change is described in second parameter as
10484// array of groups of 3 numbers:
10485// (change_begin, change_end, change_end_new_position).
10486// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010487static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010488 ASSERT(args.length() == 2);
10489 HandleScope scope;
10490 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10491 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10492
ager@chromium.orgac091b72010-05-05 07:34:42 +000010493 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010494}
10495
10496
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010497// For array of SharedFunctionInfo's (each wrapped in JSValue)
10498// checks that none of them have activations on stacks (of any thread).
10499// Returns array of the same length with corresponding results of
10500// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010501static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010502 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010503 HandleScope scope;
10504 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000010505 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010506
ager@chromium.org357bf652010-04-12 11:30:10 +000010507 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010508}
10509
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010510// Compares 2 strings line-by-line, then token-wise and returns diff in form
10511// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
10512// of diff chunks.
10513static MaybeObject* Runtime_LiveEditCompareStrings(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010514 ASSERT(args.length() == 2);
10515 HandleScope scope;
10516 CONVERT_ARG_CHECKED(String, s1, 0);
10517 CONVERT_ARG_CHECKED(String, s2, 1);
10518
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010519 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010520}
10521
10522
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010523
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010524// A testing entry. Returns statement position which is the closest to
10525// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010526static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010527 ASSERT(args.length() == 2);
10528 HandleScope scope;
10529 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10530 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10531
10532 Handle<Code> code(function->code());
10533
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010534 if (code->kind() != Code::FUNCTION &&
10535 code->kind() != Code::OPTIMIZED_FUNCTION) {
10536 return Heap::undefined_value();
10537 }
10538
10539 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010540 int closest_pc = 0;
10541 int distance = kMaxInt;
10542 while (!it.done()) {
10543 int statement_position = static_cast<int>(it.rinfo()->data());
10544 // Check if this break point is closer that what was previously found.
10545 if (source_position <= statement_position &&
10546 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000010547 closest_pc =
10548 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010549 distance = statement_position - source_position;
10550 // Check whether we can't get any closer.
10551 if (distance == 0) break;
10552 }
10553 it.next();
10554 }
10555
10556 return Smi::FromInt(closest_pc);
10557}
10558
10559
ager@chromium.org357bf652010-04-12 11:30:10 +000010560// Calls specified function with or without entering the debugger.
10561// This is used in unit tests to run code as if debugger is entered or simply
10562// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010563static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010564 ASSERT(args.length() == 2);
10565 HandleScope scope;
10566 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10567 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10568
10569 Handle<Object> result;
10570 bool pending_exception;
10571 {
10572 if (without_debugger) {
10573 result = Execution::Call(function, Top::global(), 0, NULL,
10574 &pending_exception);
10575 } else {
10576 EnterDebugger enter_debugger;
10577 result = Execution::Call(function, Top::global(), 0, NULL,
10578 &pending_exception);
10579 }
10580 }
10581 if (!pending_exception) {
10582 return *result;
10583 } else {
10584 return Failure::Exception();
10585 }
10586}
10587
10588
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010589// Sets a v8 flag.
10590static MaybeObject* Runtime_SetFlags(Arguments args) {
10591 CONVERT_CHECKED(String, arg, args[0]);
10592 SmartPointer<char> flags =
10593 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
10594 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
10595 return Heap::undefined_value();
10596}
10597
10598
10599// Performs a GC.
10600// Presently, it only does a full GC.
10601static MaybeObject* Runtime_CollectGarbage(Arguments args) {
10602 Heap::CollectAllGarbage(true);
10603 return Heap::undefined_value();
10604}
10605
10606
10607// Gets the current heap usage.
10608static MaybeObject* Runtime_GetHeapUsage(Arguments args) {
10609 int usage = static_cast<int>(Heap::SizeOfObjects());
10610 if (!Smi::IsValid(usage)) {
10611 return *Factory::NewNumberFromInt(usage);
10612 }
10613 return Smi::FromInt(usage);
10614}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010615#endif // ENABLE_DEBUGGER_SUPPORT
10616
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010617
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010618#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org303ada72010-10-27 09:33:13 +000010619static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010620 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010621 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010622
10623 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010624 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10625 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010626 return Heap::undefined_value();
10627}
10628
10629
lrn@chromium.org303ada72010-10-27 09:33:13 +000010630static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010631 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010632 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010633
10634 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010635 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10636 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010637 return Heap::undefined_value();
10638}
10639
10640#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010641
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010642// Finds the script object from the script data. NOTE: This operation uses
10643// heap traversal to find the function generated for the source position
10644// for the requested break point. For lazily compiled functions several heap
10645// traversals might be required rendering this operation as a rather slow
10646// operation. However for setting break points which is normally done through
10647// some kind of user interaction the performance is not crucial.
10648static Handle<Object> Runtime_GetScriptFromScriptName(
10649 Handle<String> script_name) {
10650 // Scan the heap for Script objects to find the script with the requested
10651 // script data.
10652 Handle<Script> script;
10653 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010654 HeapObject* obj = NULL;
10655 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010656 // If a script is found check if it has the script data requested.
10657 if (obj->IsScript()) {
10658 if (Script::cast(obj)->name()->IsString()) {
10659 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
10660 script = Handle<Script>(Script::cast(obj));
10661 }
10662 }
10663 }
10664 }
10665
10666 // If no script with the requested script data is found return undefined.
10667 if (script.is_null()) return Factory::undefined_value();
10668
10669 // Return the script found.
10670 return GetScriptWrapper(script);
10671}
10672
10673
10674// Get the script object from script data. NOTE: Regarding performance
10675// see the NOTE for GetScriptFromScriptData.
10676// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000010677static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010678 HandleScope scope;
10679
10680 ASSERT(args.length() == 1);
10681
10682 CONVERT_CHECKED(String, script_name, args[0]);
10683
10684 // Find the requested script.
10685 Handle<Object> result =
10686 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10687 return *result;
10688}
10689
10690
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010691// Determines whether the given stack frame should be displayed in
10692// a stack trace. The caller is the error constructor that asked
10693// for the stack trace to be collected. The first time a construct
10694// call to this function is encountered it is skipped. The seen_caller
10695// in/out parameter is used to remember if the caller has been seen
10696// yet.
10697static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10698 bool* seen_caller) {
10699 // Only display JS frames.
10700 if (!raw_frame->is_java_script())
10701 return false;
10702 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10703 Object* raw_fun = frame->function();
10704 // Not sure when this can happen but skip it just in case.
10705 if (!raw_fun->IsJSFunction())
10706 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010707 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010708 *seen_caller = true;
10709 return false;
10710 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010711 // Skip all frames until we've seen the caller. Also, skip the most
10712 // obvious builtin calls. Some builtin calls (such as Number.ADD
10713 // which is invoked using 'call') are very difficult to recognize
10714 // so we're leaving them in for now.
10715 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010716}
10717
10718
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010719// Collect the raw data for a stack trace. Returns an array of 4
10720// element segments each containing a receiver, function, code and
10721// native code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010722static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010723 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010724 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010725 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10726
10727 HandleScope scope;
10728
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000010729 limit = Max(limit, 0); // Ensure that limit is not negative.
10730 int initial_size = Min(limit, 10);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010731 Handle<JSArray> result = Factory::NewJSArray(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010732
10733 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010734 // If the caller parameter is a function we skip frames until we're
10735 // under it before starting to collect.
10736 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010737 int cursor = 0;
10738 int frames_seen = 0;
10739 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010740 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010741 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010742 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010743 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010744 List<FrameSummary> frames(3); // Max 2 levels of inlining.
10745 frame->Summarize(&frames);
10746 for (int i = frames.length() - 1; i >= 0; i--) {
10747 Handle<Object> recv = frames[i].receiver();
10748 Handle<JSFunction> fun = frames[i].function();
10749 Handle<Code> code = frames[i].code();
10750 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
10751 FixedArray* elements = FixedArray::cast(result->elements());
10752 if (cursor + 3 < elements->length()) {
10753 elements->set(cursor++, *recv);
10754 elements->set(cursor++, *fun);
10755 elements->set(cursor++, *code);
10756 elements->set(cursor++, *offset);
10757 } else {
10758 SetElement(result, cursor++, recv);
10759 SetElement(result, cursor++, fun);
10760 SetElement(result, cursor++, code);
10761 SetElement(result, cursor++, offset);
10762 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010763 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010764 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010765 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010766 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010767
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010768 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010769 return *result;
10770}
10771
10772
ager@chromium.org3811b432009-10-28 14:53:37 +000010773// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010774static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010775 ASSERT_EQ(args.length(), 0);
10776
10777 NoHandleAllocation ha;
10778
10779 const char* version_string = v8::V8::GetVersion();
10780
10781 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
10782}
10783
10784
lrn@chromium.org303ada72010-10-27 09:33:13 +000010785static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010786 ASSERT(args.length() == 2);
10787 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10788 Smi::cast(args[1])->value());
10789 Top::PrintStack();
10790 OS::Abort();
10791 UNREACHABLE();
10792 return NULL;
10793}
10794
10795
lrn@chromium.org303ada72010-10-27 09:33:13 +000010796static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010797 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010798 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010799 Object* key = args[1];
10800
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010801 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010802 Object* o = cache->get(finger_index);
10803 if (o == key) {
10804 // The fastest case: hit the same place again.
10805 return cache->get(finger_index + 1);
10806 }
10807
10808 for (int i = finger_index - 2;
10809 i >= JSFunctionResultCache::kEntriesIndex;
10810 i -= 2) {
10811 o = cache->get(i);
10812 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010813 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010814 return cache->get(i + 1);
10815 }
10816 }
10817
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010818 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010819 ASSERT(size <= cache->length());
10820
10821 for (int i = size - 2; i > finger_index; i -= 2) {
10822 o = cache->get(i);
10823 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010824 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010825 return cache->get(i + 1);
10826 }
10827 }
10828
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010829 // There is no value in the cache. Invoke the function and cache result.
10830 HandleScope scope;
10831
10832 Handle<JSFunctionResultCache> cache_handle(cache);
10833 Handle<Object> key_handle(key);
10834 Handle<Object> value;
10835 {
10836 Handle<JSFunction> factory(JSFunction::cast(
10837 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
10838 // TODO(antonm): consider passing a receiver when constructing a cache.
10839 Handle<Object> receiver(Top::global_context()->global());
10840 // This handle is nor shared, nor used later, so it's safe.
10841 Object** argv[] = { key_handle.location() };
10842 bool pending_exception = false;
10843 value = Execution::Call(factory,
10844 receiver,
10845 1,
10846 argv,
10847 &pending_exception);
10848 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010849 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010850
10851#ifdef DEBUG
10852 cache_handle->JSFunctionResultCacheVerify();
10853#endif
10854
10855 // Function invocation may have cleared the cache. Reread all the data.
10856 finger_index = cache_handle->finger_index();
10857 size = cache_handle->size();
10858
10859 // If we have spare room, put new data into it, otherwise evict post finger
10860 // entry which is likely to be the least recently used.
10861 int index = -1;
10862 if (size < cache_handle->length()) {
10863 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
10864 index = size;
10865 } else {
10866 index = finger_index + JSFunctionResultCache::kEntrySize;
10867 if (index == cache_handle->length()) {
10868 index = JSFunctionResultCache::kEntriesIndex;
10869 }
10870 }
10871
10872 ASSERT(index % 2 == 0);
10873 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
10874 ASSERT(index < cache_handle->length());
10875
10876 cache_handle->set(index, *key_handle);
10877 cache_handle->set(index + 1, *value);
10878 cache_handle->set_finger_index(index);
10879
10880#ifdef DEBUG
10881 cache_handle->JSFunctionResultCacheVerify();
10882#endif
10883
10884 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010885}
10886
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000010887
10888static MaybeObject* Runtime_NewMessageObject(Arguments args) {
10889 HandleScope scope;
10890 CONVERT_ARG_CHECKED(String, type, 0);
10891 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
10892 return *Factory::NewJSMessageObject(type,
10893 arguments,
10894 0,
10895 0,
10896 Factory::undefined_value(),
10897 Factory::undefined_value(),
10898 Factory::undefined_value());
10899}
10900
10901
10902static MaybeObject* Runtime_MessageGetType(Arguments args) {
10903 CONVERT_CHECKED(JSMessageObject, message, args[0]);
10904 return message->type();
10905}
10906
10907
10908static MaybeObject* Runtime_MessageGetArguments(Arguments args) {
10909 CONVERT_CHECKED(JSMessageObject, message, args[0]);
10910 return message->arguments();
10911}
10912
10913
10914static MaybeObject* Runtime_MessageGetStartPosition(Arguments args) {
10915 CONVERT_CHECKED(JSMessageObject, message, args[0]);
10916 return Smi::FromInt(message->start_position());
10917}
10918
10919
10920static MaybeObject* Runtime_MessageGetScript(Arguments args) {
10921 CONVERT_CHECKED(JSMessageObject, message, args[0]);
10922 return message->script();
10923}
10924
10925
kasper.lund44510672008-07-25 07:37:58 +000010926#ifdef DEBUG
10927// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10928// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010929static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010930 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010931 HandleScope scope;
10932 Handle<JSArray> result = Factory::NewJSArray(0);
10933 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010934 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010935#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010936 { \
10937 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010938 Handle<String> name; \
10939 /* Inline runtime functions have an underscore in front of the name. */ \
10940 if (inline_runtime_functions) { \
10941 name = Factory::NewStringFromAscii( \
10942 Vector<const char>("_" #Name, StrLength("_" #Name))); \
10943 } else { \
10944 name = Factory::NewStringFromAscii( \
10945 Vector<const char>(#Name, StrLength(#Name))); \
10946 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010947 Handle<JSArray> pair = Factory::NewJSArray(0); \
10948 SetElement(pair, 0, name); \
10949 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
10950 SetElement(result, index++, pair); \
10951 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010952 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010953 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010954 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010955 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010956 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010957#undef ADD_ENTRY
10958 return *result;
10959}
kasper.lund44510672008-07-25 07:37:58 +000010960#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010961
10962
lrn@chromium.org303ada72010-10-27 09:33:13 +000010963static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010964 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010965 CONVERT_CHECKED(String, format, args[0]);
10966 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010967 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010968 Logger::LogRuntime(chars, elms);
10969 return Heap::undefined_value();
10970}
10971
10972
lrn@chromium.org303ada72010-10-27 09:33:13 +000010973static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010974 UNREACHABLE(); // implemented as macro in the parser
10975 return NULL;
10976}
10977
10978
10979// ----------------------------------------------------------------------------
10980// Implementation of Runtime
10981
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010982#define F(name, number_of_args, result_size) \
10983 { Runtime::k##name, Runtime::RUNTIME, #name, \
10984 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010985
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010986
10987#define I(name, number_of_args, result_size) \
10988 { Runtime::kInline##name, Runtime::INLINE, \
10989 "_" #name, NULL, number_of_args, result_size },
10990
10991Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010992 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010993 INLINE_FUNCTION_LIST(I)
10994 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010995};
10996
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010997
lrn@chromium.org303ada72010-10-27 09:33:13 +000010998MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010999 ASSERT(dictionary != NULL);
11000 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
11001 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011002 Object* name_symbol;
11003 { MaybeObject* maybe_name_symbol =
11004 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
11005 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
11006 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011007 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011008 { MaybeObject* maybe_dictionary = string_dictionary->Add(
11009 String::cast(name_symbol),
11010 Smi::FromInt(i),
11011 PropertyDetails(NONE, NORMAL));
11012 if (!maybe_dictionary->ToObject(&dictionary)) {
11013 // Non-recoverable failure. Calling code must restart heap
11014 // initialization.
11015 return maybe_dictionary;
11016 }
11017 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011018 }
11019 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011020}
11021
11022
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011023Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
11024 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
11025 if (entry != kNotFound) {
11026 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
11027 int function_index = Smi::cast(smi_index)->value();
11028 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011029 }
11030 return NULL;
11031}
11032
11033
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011034Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
11035 return &(kIntrinsicFunctions[static_cast<int>(id)]);
11036}
11037
11038
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011039void Runtime::PerformGC(Object* result) {
11040 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011041 if (failure->IsRetryAfterGC()) {
11042 // Try to do a garbage collection; ignore it if it fails. The C
11043 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000011044 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011045 } else {
11046 // Handle last resort GC and make sure to allow future allocations
11047 // to grow the heap without causing GCs (if possible).
11048 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000011049 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011050 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011051}
11052
11053
11054} } // namespace v8::internal