blob: b687057db9fe3bd11a195e8819aca90576e633ae [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 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"
35#include "compiler.h"
36#include "cpu.h"
37#include "dateparser.h"
38#include "debug.h"
39#include "execution.h"
40#include "jsregexp.h"
41#include "platform.h"
42#include "runtime.h"
43#include "scopeinfo.h"
44#include "v8threads.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000045#include "smart-pointer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046
47namespace v8 { namespace internal {
48
49
50#define RUNTIME_ASSERT(value) do { \
51 if (!(value)) return IllegalOperation(); \
52} while (false)
53
54// Cast the given object to a value of the specified type and store
55// it in a variable with the given name. If the object is not of the
56// expected type call IllegalOperation and return.
57#define CONVERT_CHECKED(Type, name, obj) \
58 RUNTIME_ASSERT(obj->Is##Type()); \
59 Type* name = Type::cast(obj);
60
61#define CONVERT_ARG_CHECKED(Type, name, index) \
62 RUNTIME_ASSERT(args[index]->Is##Type()); \
63 Handle<Type> name = args.at<Type>(index);
64
kasper.lundbd3ec4e2008-07-09 11:06:54 +000065// Cast the given object to a boolean and store it in a variable with
66// the given name. If the object is not a boolean call IllegalOperation
67// and return.
68#define CONVERT_BOOLEAN_CHECKED(name, obj) \
69 RUNTIME_ASSERT(obj->IsBoolean()); \
70 bool name = (obj)->IsTrue();
71
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072// Cast the given object to a double and store it in a variable with
73// the given name. If the object is not a number (as opposed to
74// the number not-a-number) call IllegalOperation and return.
75#define CONVERT_DOUBLE_CHECKED(name, obj) \
76 RUNTIME_ASSERT(obj->IsNumber()); \
77 double name = (obj)->Number();
78
79// Call the specified converter on the object *comand store the result in
80// a variable of the specified type with the given name. If the
81// object is not a Number call IllegalOperation and return.
82#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
83 RUNTIME_ASSERT(obj->IsNumber()); \
84 type name = NumberTo##Type(obj);
85
86// Non-reentrant string buffer for efficient general use in this file.
87static StaticResource<StringInputBuffer> string_input_buffer;
88
89
90static Object* IllegalOperation() {
91 return Top::Throw(Heap::illegal_access_symbol());
92}
93
94
95static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) {
96 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000097 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098}
99
100
ager@chromium.org236ad962008-09-25 09:45:57 +0000101static Handle<Map> ComputeObjectLiteralMap(
102 Handle<Context> context,
103 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000104 bool* is_result_from_cache) {
ager@chromium.org32912102009-01-16 10:38:43 +0000105 int number_of_properties = constant_properties->length() / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000106 if (FLAG_canonicalize_object_literal_maps) {
107 // First find prefix of consecutive symbol keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000108 int number_of_symbol_keys = 0;
109 while ((number_of_symbol_keys < number_of_properties) &&
110 (constant_properties->get(number_of_symbol_keys*2)->IsSymbol())) {
111 number_of_symbol_keys++;
112 }
113 // Based on the number of prefix symbols key we decide whether
114 // to use the map cache in the global context.
115 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000116 if ((number_of_symbol_keys == number_of_properties) &&
117 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000118 // Create the fixed array with the key.
119 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
120 for (int i = 0; i < number_of_symbol_keys; i++) {
121 keys->set(i, constant_properties->get(i*2));
122 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000123 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000124 return Factory::ObjectLiteralMapFromCache(context, keys);
125 }
126 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000127 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000128 return Factory::CopyMap(
129 Handle<Map>(context->object_function()->initial_map()),
130 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000131}
132
133
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000134static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
135 HandleScope scope;
136 ASSERT(args.length() == 3);
137 // Copy the arguments.
138 Handle<FixedArray> literals = args.at<FixedArray>(0);
139 int literals_index = Smi::cast(args[1])->value();
140 Handle<FixedArray> constant_properties = args.at<FixedArray>(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000141
142 // Get the global context from the literals array. This is the
143 // context in which the function was created and we use the object
144 // function from this context to create the object literal. We do
145 // not use the object function from the current global context
146 // because this might be the object function from another context
147 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000148 Handle<Context> context =
149 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
150
151 bool is_result_from_cache;
152 Handle<Map> map = ComputeObjectLiteralMap(context,
153 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000154 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000155
ager@chromium.org236ad962008-09-25 09:45:57 +0000156 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
ager@chromium.org32912102009-01-16 10:38:43 +0000157 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000159 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
160 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000161 for (int index = 0; index < length; index +=2) {
162 Handle<Object> key(constant_properties->get(index+0));
163 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000164 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000165 uint32_t element_index = 0;
166 if (key->IsSymbol()) {
167 // If key is a symbol it is not an array element.
168 Handle<String> name(String::cast(*key));
169 ASSERT(!name->AsArrayIndex(&element_index));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000170 result = SetProperty(boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000171 } else if (Array::IndexFromObject(*key, &element_index)) {
172 // Array index (uint32).
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000173 result = SetElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000174 } else {
175 // Non-uint32 number.
176 ASSERT(key->IsNumber());
177 double num = key->Number();
178 char arr[100];
179 Vector<char> buffer(arr, ARRAY_SIZE(arr));
180 const char* str = DoubleToCString(num, buffer);
181 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000182 result = SetProperty(boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000183 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000184 // If setting the property on the boilerplate throws an
185 // exception, the exception is converted to an empty handle in
186 // the handle based operations. In that case, we need to
187 // convert back to an exception.
188 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000189 }
190 }
191
192 // Update the functions literal and return the boilerplate.
193 literals->set(literals_index, *boilerplate);
194
195 return *boilerplate;
196}
197
198
199static Object* Runtime_CreateArrayLiteral(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000200 // Takes a FixedArray of elements containing the literal elements of
201 // the array literal and produces JSArray with those elements.
202 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000203 // which contains the context from which to get the Array function
204 // to use for creating the array literal.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000205 ASSERT(args.length() == 2);
206 CONVERT_CHECKED(FixedArray, elements, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000207 CONVERT_CHECKED(FixedArray, literals, args[1]);
ager@chromium.org236ad962008-09-25 09:45:57 +0000208 JSFunction* constructor =
209 JSFunction::GlobalContextFromLiterals(literals)->array_function();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000210 // Create the JSArray.
211 Object* object = Heap::AllocateJSObject(constructor);
212 if (object->IsFailure()) return object;
213
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000214 // Copy the elements.
215 Object* content = elements->Copy();
216 if (content->IsFailure()) return content;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000217
218 // Set the elements.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000219 JSArray::cast(object)->SetContent(FixedArray::cast(content));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000220 return object;
221}
222
223
ager@chromium.org32912102009-01-16 10:38:43 +0000224static Object* Runtime_CreateCatchExtensionObject(Arguments args) {
225 ASSERT(args.length() == 2);
226 CONVERT_CHECKED(String, key, args[0]);
227 Object* value = args[1];
228 // Create a catch context extension object.
229 JSFunction* constructor =
230 Top::context()->global_context()->context_extension_function();
231 Object* object = Heap::AllocateJSObject(constructor);
232 if (object->IsFailure()) return object;
233 // Assign the exception value to the catch variable and make sure
234 // that the catch variable is DontDelete.
235 value = JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
236 if (value->IsFailure()) return value;
237 return object;
238}
239
240
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000241static Object* Runtime_ClassOf(Arguments args) {
242 NoHandleAllocation ha;
243 ASSERT(args.length() == 1);
244 Object* obj = args[0];
245 if (!obj->IsJSObject()) return Heap::null_value();
246 return JSObject::cast(obj)->class_name();
247}
248
ager@chromium.org7c537e22008-10-16 08:43:32 +0000249
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000250static Object* Runtime_HasStringClass(Arguments args) {
251 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::String_symbol()));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000252}
253
254
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000255static Object* Runtime_HasDateClass(Arguments args) {
256 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Date_symbol()));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000257}
258
259
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000260static Object* Runtime_HasArrayClass(Arguments args) {
261 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Array_symbol()));
262}
263
264
265static Object* Runtime_HasFunctionClass(Arguments args) {
266 return Heap::ToBoolean(
267 args[0]->HasSpecificClassOf(Heap::function_class_symbol()));
268}
269
270
271static Object* Runtime_HasNumberClass(Arguments args) {
272 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Number_symbol()));
273}
274
275
276static Object* Runtime_HasBooleanClass(Arguments args) {
277 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Boolean_symbol()));
278}
279
280
281static Object* Runtime_HasArgumentsClass(Arguments args) {
282 return Heap::ToBoolean(
283 args[0]->HasSpecificClassOf(Heap::Arguments_symbol()));
284}
285
286
287static Object* Runtime_HasRegExpClass(Arguments args) {
288 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::RegExp_symbol()));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000289}
290
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000291
292static Object* Runtime_IsInPrototypeChain(Arguments args) {
293 NoHandleAllocation ha;
294 ASSERT(args.length() == 2);
295 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
296 Object* O = args[0];
297 Object* V = args[1];
298 while (true) {
299 Object* prototype = V->GetPrototype();
300 if (prototype->IsNull()) return Heap::false_value();
301 if (O == prototype) return Heap::true_value();
302 V = prototype;
303 }
304}
305
306
307static Object* Runtime_IsConstructCall(Arguments args) {
308 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000309 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000310 JavaScriptFrameIterator it;
311 return Heap::ToBoolean(it.frame()->IsConstructor());
312}
313
314
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000315static Object* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000316 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317 ASSERT(args.length() == 3);
ager@chromium.org236ad962008-09-25 09:45:57 +0000318 CONVERT_CHECKED(JSRegExp, raw_re, args[0]);
319 Handle<JSRegExp> re(raw_re);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320 CONVERT_CHECKED(String, raw_pattern, args[1]);
321 Handle<String> pattern(raw_pattern);
322 CONVERT_CHECKED(String, raw_flags, args[2]);
323 Handle<String> flags(raw_flags);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000324 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
325 if (result.is_null()) return Failure::Exception();
326 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327}
328
329
330static Object* Runtime_CreateApiFunction(Arguments args) {
331 HandleScope scope;
332 ASSERT(args.length() == 1);
333 CONVERT_CHECKED(FunctionTemplateInfo, raw_data, args[0]);
334 Handle<FunctionTemplateInfo> data(raw_data);
335 return *Factory::CreateApiFunction(data);
336}
337
338
339static Object* Runtime_IsTemplate(Arguments args) {
340 ASSERT(args.length() == 1);
341 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000342 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 return Heap::ToBoolean(result);
344}
345
346
347static Object* Runtime_GetTemplateField(Arguments args) {
348 ASSERT(args.length() == 2);
349 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000350 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000351 int index = field->value();
352 int offset = index * kPointerSize + HeapObject::kHeaderSize;
353 InstanceType type = templ->map()->instance_type();
354 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
355 type == OBJECT_TEMPLATE_INFO_TYPE);
356 RUNTIME_ASSERT(offset > 0);
357 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
358 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
359 } else {
360 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
361 }
362 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000363}
364
365
ager@chromium.org870a0b62008-11-04 11:43:05 +0000366static Object* Runtime_DisableAccessChecks(Arguments args) {
367 ASSERT(args.length() == 1);
368 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000369 Map* old_map = object->map();
370 bool needs_access_checks = old_map->is_access_check_needed();
371 if (needs_access_checks) {
372 // Copy map so it won't interfere constructor's initial map.
373 Object* new_map = old_map->CopyDropTransitions();
374 if (new_map->IsFailure()) return new_map;
375
376 Map::cast(new_map)->set_is_access_check_needed(false);
377 object->set_map(Map::cast(new_map));
378 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000379 return needs_access_checks ? Heap::true_value() : Heap::false_value();
380}
381
382
383static Object* Runtime_EnableAccessChecks(Arguments args) {
384 ASSERT(args.length() == 1);
385 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000386 Map* old_map = object->map();
387 if (!old_map->is_access_check_needed()) {
388 // Copy map so it won't interfere constructor's initial map.
389 Object* new_map = old_map->CopyDropTransitions();
390 if (new_map->IsFailure()) return new_map;
391
392 Map::cast(new_map)->set_is_access_check_needed(true);
393 object->set_map(Map::cast(new_map));
394 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000395 return Heap::undefined_value();
396}
397
398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399static Object* ThrowRedeclarationError(const char* type, Handle<String> name) {
400 HandleScope scope;
401 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
402 Handle<Object> args[2] = { type_handle, name };
403 Handle<Object> error =
404 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
405 return Top::Throw(*error);
406}
407
408
409static Object* Runtime_DeclareGlobals(Arguments args) {
410 HandleScope scope;
411 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
412
413 CONVERT_ARG_CHECKED(FixedArray, pairs, 0);
414 Handle<Context> context = args.at<Context>(1);
415 bool is_eval = Smi::cast(args[2])->value() == 1;
416
417 // Compute the property attributes. According to ECMA-262, section
418 // 13, page 71, the property must be read-only and
419 // non-deletable. However, neither SpiderMonkey nor KJS creates the
420 // property as read-only, so we don't either.
421 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
422
423 // Only optimize the object if we intend to add more than 5 properties.
424 OptimizedObjectForAddingMultipleProperties ba(global, pairs->length()/2 > 5);
425
426 // Traverse the name/value pairs and set the properties.
427 int length = pairs->length();
428 for (int i = 0; i < length; i += 2) {
429 HandleScope scope;
430 Handle<String> name(String::cast(pairs->get(i)));
431 Handle<Object> value(pairs->get(i + 1));
432
433 // We have to declare a global const property. To capture we only
434 // assign to it when evaluating the assignment for "const x =
435 // <expr>" the initial value is the hole.
436 bool is_const_property = value->IsTheHole();
437
438 if (value->IsUndefined() || is_const_property) {
439 // Lookup the property in the global object, and don't set the
440 // value of the variable if the property is already there.
441 LookupResult lookup;
442 global->Lookup(*name, &lookup);
443 if (lookup.IsProperty()) {
444 // Determine if the property is local by comparing the holder
445 // against the global object. The information will be used to
446 // avoid throwing re-declaration errors when declaring
447 // variables or constants that exist in the prototype chain.
448 bool is_local = (*global == lookup.holder());
449 // Get the property attributes and determine if the property is
450 // read-only.
451 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
452 bool is_read_only = (attributes & READ_ONLY) != 0;
453 if (lookup.type() == INTERCEPTOR) {
454 // If the interceptor says the property is there, we
455 // just return undefined without overwriting the property.
456 // Otherwise, we continue to setting the property.
457 if (attributes != ABSENT) {
458 // Check if the existing property conflicts with regards to const.
459 if (is_local && (is_read_only || is_const_property)) {
460 const char* type = (is_read_only) ? "const" : "var";
461 return ThrowRedeclarationError(type, name);
462 };
463 // The property already exists without conflicting: Go to
464 // the next declaration.
465 continue;
466 }
467 // Fall-through and introduce the absent property by using
468 // SetProperty.
469 } else {
470 if (is_local && (is_read_only || is_const_property)) {
471 const char* type = (is_read_only) ? "const" : "var";
472 return ThrowRedeclarationError(type, name);
473 }
474 // The property already exists without conflicting: Go to
475 // the next declaration.
476 continue;
477 }
478 }
479 } else {
480 // Copy the function and update its context. Use it as value.
481 Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(value);
482 Handle<JSFunction> function =
483 Factory::NewFunctionFromBoilerplate(boilerplate, context);
484 value = function;
485 }
486
487 LookupResult lookup;
488 global->LocalLookup(*name, &lookup);
489
490 PropertyAttributes attributes = is_const_property
491 ? static_cast<PropertyAttributes>(base | READ_ONLY)
492 : base;
493
494 if (lookup.IsProperty()) {
495 // There's a local property that we need to overwrite because
496 // we're either declaring a function or there's an interceptor
497 // that claims the property is absent.
498
499 // Check for conflicting re-declarations. We cannot have
500 // conflicting types in case of intercepted properties because
501 // they are absent.
502 if (lookup.type() != INTERCEPTOR &&
503 (lookup.IsReadOnly() || is_const_property)) {
504 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
505 return ThrowRedeclarationError(type, name);
506 }
507 SetProperty(global, name, value, attributes);
508 } else {
509 // If a property with this name does not already exist on the
510 // global object add the property locally. We take special
511 // precautions to always add it as a local property even in case
512 // of callbacks in the prototype chain (this rules out using
513 // SetProperty). Also, we must use the handle-based version to
514 // avoid GC issues.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000515 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000516 }
517 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000518
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000519 return Heap::undefined_value();
520}
521
522
523static Object* Runtime_DeclareContextSlot(Arguments args) {
524 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000525 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000526
ager@chromium.org7c537e22008-10-16 08:43:32 +0000527 CONVERT_ARG_CHECKED(Context, context, 0);
528 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000529 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +0000530 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531 ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000532 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000533
534 // Declarations are always done in the function context.
535 context = Handle<Context>(context->fcontext());
536
537 int index;
538 PropertyAttributes attributes;
539 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000540 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000541 context->Lookup(name, flags, &index, &attributes);
542
543 if (attributes != ABSENT) {
544 // The name was declared before; check for conflicting
545 // re-declarations: This is similar to the code in parser.cc in
546 // the AstBuildingParser::Declare function.
547 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
548 // Functions are not read-only.
549 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
550 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
551 return ThrowRedeclarationError(type, name);
552 }
553
554 // Initialize it if necessary.
555 if (*initial_value != NULL) {
556 if (index >= 0) {
557 // The variable or constant context slot should always be in
558 // the function context; not in any outer context nor in the
559 // arguments object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000560 ASSERT(holder.is_identical_to(context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000561 if (((attributes & READ_ONLY) == 0) ||
562 context->get(index)->IsTheHole()) {
563 context->set(index, *initial_value);
564 }
565 } else {
566 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000567 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568 SetProperty(context_ext, name, initial_value, mode);
569 }
570 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000571
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000572 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000573 // The property is not in the function context. It needs to be
574 // "declared" in the function context's extension context, or in the
575 // global context.
576 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000577 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000578 // The function context's extension context exists - use it.
579 context_ext = Handle<JSObject>(context->extension());
580 } else {
581 // The function context's extension context does not exists - allocate
582 // it.
583 context_ext = Factory::NewJSObject(Top::context_extension_function());
584 // And store it in the extension slot.
585 context->set_extension(*context_ext);
586 }
587 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000588
ager@chromium.org7c537e22008-10-16 08:43:32 +0000589 // Declare the property by setting it to the initial value if provided,
590 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
591 // constant declarations).
592 ASSERT(!context_ext->HasLocalProperty(*name));
593 Handle<Object> value(Heap::undefined_value());
594 if (*initial_value != NULL) value = initial_value;
595 SetProperty(context_ext, name, value, mode);
596 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
597 }
598
599 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600}
601
602
603static Object* Runtime_InitializeVarGlobal(Arguments args) {
604 NoHandleAllocation nha;
605
606 // Determine if we need to assign to the variable if it already
607 // exists (based on the number of arguments).
608 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
609 bool assign = args.length() == 2;
610
611 CONVERT_ARG_CHECKED(String, name, 0);
612 GlobalObject* global = Top::context()->global();
613
614 // According to ECMA-262, section 12.2, page 62, the property must
615 // not be deletable.
616 PropertyAttributes attributes = DONT_DELETE;
617
618 // Lookup the property locally in the global object. If it isn't
619 // there, we add the property and take special precautions to always
620 // add it as a local property even in case of callbacks in the
621 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000622 // We have IgnoreAttributesAndSetLocalProperty for this.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 LookupResult lookup;
624 global->LocalLookup(*name, &lookup);
625 if (!lookup.IsProperty()) {
626 Object* value = (assign) ? args[1] : Heap::undefined_value();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000627 return global->IgnoreAttributesAndSetLocalProperty(*name,
628 value,
629 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000630 }
631
632 // Determine if this is a redeclaration of something read-only.
633 if (lookup.IsReadOnly()) {
634 return ThrowRedeclarationError("const", name);
635 }
636
637 // Determine if this is a redeclaration of an intercepted read-only
638 // property and figure out if the property exists at all.
639 bool found = true;
640 PropertyType type = lookup.type();
641 if (type == INTERCEPTOR) {
642 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
643 if (intercepted == ABSENT) {
644 // The interceptor claims the property isn't there. We need to
645 // make sure to introduce it.
646 found = false;
647 } else if ((intercepted & READ_ONLY) != 0) {
648 // The property is present, but read-only. Since we're trying to
649 // overwrite it with a variable declaration we must throw a
650 // re-declaration error.
651 return ThrowRedeclarationError("const", name);
652 }
653 // Restore global object from context (in case of GC).
654 global = Top::context()->global();
655 }
656
657 if (found && !assign) {
658 // The global property is there and we're not assigning any value
659 // to it. Just return.
660 return Heap::undefined_value();
661 }
662
663 // Assign the value (or undefined) to the property.
664 Object* value = (assign) ? args[1] : Heap::undefined_value();
665 return global->SetProperty(&lookup, *name, value, attributes);
666}
667
668
669static Object* Runtime_InitializeConstGlobal(Arguments args) {
670 // All constants are declared with an initial value. The name
671 // of the constant is the first argument and the initial value
672 // is the second.
673 RUNTIME_ASSERT(args.length() == 2);
674 CONVERT_ARG_CHECKED(String, name, 0);
675 Handle<Object> value = args.at<Object>(1);
676
677 // Get the current global object from top.
678 GlobalObject* global = Top::context()->global();
679
680 // According to ECMA-262, section 12.2, page 62, the property must
681 // not be deletable. Since it's a const, it must be READ_ONLY too.
682 PropertyAttributes attributes =
683 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
684
685 // Lookup the property locally in the global object. If it isn't
686 // there, we add the property and take special precautions to always
687 // add it as a local property even in case of callbacks in the
688 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000689 // We use IgnoreAttributesAndSetLocalProperty instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000690 LookupResult lookup;
691 global->LocalLookup(*name, &lookup);
692 if (!lookup.IsProperty()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000693 return global->IgnoreAttributesAndSetLocalProperty(*name,
694 *value,
695 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696 }
697
698 // Determine if this is a redeclaration of something not
699 // read-only. In case the result is hidden behind an interceptor we
700 // need to ask it for the property attributes.
701 if (!lookup.IsReadOnly()) {
702 if (lookup.type() != INTERCEPTOR) {
703 return ThrowRedeclarationError("var", name);
704 }
705
706 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
707
708 // Throw re-declaration error if the intercepted property is present
709 // but not read-only.
710 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
711 return ThrowRedeclarationError("var", name);
712 }
713
714 // Restore global object from context (in case of GC) and continue
715 // with setting the value because the property is either absent or
716 // read-only. We also have to do redo the lookup.
717 global = Top::context()->global();
718
719 // BUG 1213579: Handle the case where we have to set a read-only
720 // property through an interceptor and only do it if it's
721 // uninitialized, e.g. the hole. Nirk...
722 global->SetProperty(*name, *value, attributes);
723 return *value;
724 }
725
726 // Set the value, but only we're assigning the initial value to a
727 // constant. For now, we determine this by checking if the
728 // current value is the hole.
729 PropertyType type = lookup.type();
730 if (type == FIELD) {
731 FixedArray* properties = global->properties();
732 int index = lookup.GetFieldIndex();
733 if (properties->get(index)->IsTheHole()) {
734 properties->set(index, *value);
735 }
736 } else if (type == NORMAL) {
737 Dictionary* dictionary = global->property_dictionary();
738 int entry = lookup.GetDictionaryEntry();
739 if (dictionary->ValueAt(entry)->IsTheHole()) {
740 dictionary->ValueAtPut(entry, *value);
741 }
742 } else {
743 // Ignore re-initialization of constants that have already been
744 // assigned a function value.
745 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
746 }
747
748 // Use the set value as the result of the operation.
749 return *value;
750}
751
752
753static Object* Runtime_InitializeConstContextSlot(Arguments args) {
754 HandleScope scope;
755 ASSERT(args.length() == 3);
756
757 Handle<Object> value(args[0]);
758 ASSERT(!value->IsTheHole());
759 CONVERT_ARG_CHECKED(Context, context, 1);
760 Handle<String> name(String::cast(args[2]));
761
762 // Initializations are always done in the function context.
763 context = Handle<Context>(context->fcontext());
764
765 int index;
766 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000767 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000768 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769 context->Lookup(name, flags, &index, &attributes);
770
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000771 // In most situations, the property introduced by the const
772 // declaration should be present in the context extension object.
773 // However, because declaration and initialization are separate, the
774 // property might have been deleted (if it was introduced by eval)
775 // before we reach the initialization point.
776 //
777 // Example:
778 //
779 // function f() { eval("delete x; const x;"); }
780 //
781 // In that case, the initialization behaves like a normal assignment
782 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000783 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000784 // Property was found in a context.
785 if (holder->IsContext()) {
786 // The holder cannot be the function context. If it is, there
787 // should have been a const redeclaration error when declaring
788 // the const property.
789 ASSERT(!holder.is_identical_to(context));
790 if ((attributes & READ_ONLY) == 0) {
791 Handle<Context>::cast(holder)->set(index, *value);
792 }
793 } else {
794 // The holder is an arguments object.
795 ASSERT((attributes & READ_ONLY) == 0);
796 Handle<JSObject>::cast(holder)->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000797 }
798 return *value;
799 }
800
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000801 // The property could not be found, we introduce it in the global
802 // context.
803 if (attributes == ABSENT) {
804 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
805 SetProperty(global, name, value, NONE);
806 return *value;
807 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000809 // The property was present in a context extension object.
810 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000811
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000812 if (*context_ext == context->extension()) {
813 // This is the property that was introduced by the const
814 // declaration. Set it if it hasn't been set before. NOTE: We
815 // cannot use GetProperty() to get the current value as it
816 // 'unholes' the value.
817 LookupResult lookup;
818 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
819 ASSERT(lookup.IsProperty()); // the property was declared
820 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
821
822 PropertyType type = lookup.type();
823 if (type == FIELD) {
824 FixedArray* properties = context_ext->properties();
825 int index = lookup.GetFieldIndex();
826 if (properties->get(index)->IsTheHole()) {
827 properties->set(index, *value);
828 }
829 } else if (type == NORMAL) {
830 Dictionary* dictionary = context_ext->property_dictionary();
831 int entry = lookup.GetDictionaryEntry();
832 if (dictionary->ValueAt(entry)->IsTheHole()) {
833 dictionary->ValueAtPut(entry, *value);
834 }
835 } else {
836 // We should not reach here. Any real, named property should be
837 // either a field or a dictionary slot.
838 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000839 }
840 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000841 // The property was found in a different context extension object.
842 // Set it if it is not a read-only property.
843 if ((attributes & READ_ONLY) == 0) {
844 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
845 // Setting a property might throw an exception. Exceptions
846 // are converted to empty handles in handle operations. We
847 // need to convert back to exceptions here.
848 if (set.is_null()) {
849 ASSERT(Top::has_pending_exception());
850 return Failure::Exception();
851 }
852 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000853 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000854
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000855 return *value;
856}
857
858
859static Object* Runtime_RegExpExec(Arguments args) {
860 HandleScope scope;
861 ASSERT(args.length() == 3);
ager@chromium.org236ad962008-09-25 09:45:57 +0000862 CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
863 Handle<JSRegExp> regexp(raw_regexp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000864 CONVERT_CHECKED(String, raw_subject, args[1]);
865 Handle<String> subject(raw_subject);
866 Handle<Object> index(args[2]);
867 ASSERT(index->IsNumber());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000868 Handle<Object> result = RegExpImpl::Exec(regexp, subject, index);
869 if (result.is_null()) return Failure::Exception();
870 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871}
872
873
874static Object* Runtime_RegExpExecGlobal(Arguments args) {
875 HandleScope scope;
876 ASSERT(args.length() == 2);
ager@chromium.org236ad962008-09-25 09:45:57 +0000877 CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
878 Handle<JSRegExp> regexp(raw_regexp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000879 CONVERT_CHECKED(String, raw_subject, args[1]);
880 Handle<String> subject(raw_subject);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000881 Handle<Object> result = RegExpImpl::ExecGlobal(regexp, subject);
882 if (result.is_null()) return Failure::Exception();
883 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000884}
885
886
887static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
888 HandleScope scope;
889 ASSERT(args.length() == 4);
890 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
891 int index = Smi::cast(args[1])->value();
892 Handle<String> pattern = args.at<String>(2);
893 Handle<String> flags = args.at<String>(3);
894
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000895 // Get the RegExp function from the context in the literals array.
896 // This is the RegExp function from the context in which the
897 // function was created. We do not use the RegExp function from the
898 // current global context because this might be the RegExp function
899 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000900 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +0000901 Handle<JSFunction>(
902 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000903 // Compute the regular expression literal.
904 bool has_pending_exception;
905 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000906 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
907 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000908 if (has_pending_exception) {
909 ASSERT(Top::has_pending_exception());
910 return Failure::Exception();
911 }
912 literals->set(index, *regexp);
913 return *regexp;
914}
915
916
917static Object* Runtime_FunctionGetName(Arguments args) {
918 NoHandleAllocation ha;
919 ASSERT(args.length() == 1);
920
921 CONVERT_CHECKED(JSFunction, f, args[0]);
922 return f->shared()->name();
923}
924
925
ager@chromium.org236ad962008-09-25 09:45:57 +0000926static Object* Runtime_FunctionSetName(Arguments args) {
927 NoHandleAllocation ha;
928 ASSERT(args.length() == 2);
929
930 CONVERT_CHECKED(JSFunction, f, args[0]);
931 CONVERT_CHECKED(String, name, args[1]);
932 f->shared()->set_name(name);
933 return Heap::undefined_value();
934}
935
936
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000937static Object* Runtime_FunctionGetScript(Arguments args) {
938 HandleScope scope;
939 ASSERT(args.length() == 1);
940
941 CONVERT_CHECKED(JSFunction, fun, args[0]);
942 Handle<Object> script = Handle<Object>(fun->shared()->script());
943 if (!script->IsScript()) return Heap::undefined_value();
944
945 return *GetScriptWrapper(Handle<Script>::cast(script));
946}
947
948
949static Object* Runtime_FunctionGetSourceCode(Arguments args) {
950 NoHandleAllocation ha;
951 ASSERT(args.length() == 1);
952
953 CONVERT_CHECKED(JSFunction, f, args[0]);
954 return f->shared()->GetSourceCode();
955}
956
957
958static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
959 NoHandleAllocation ha;
960 ASSERT(args.length() == 1);
961
962 CONVERT_CHECKED(JSFunction, fun, args[0]);
963 int pos = fun->shared()->start_position();
964 return Smi::FromInt(pos);
965}
966
967
968static Object* Runtime_FunctionSetInstanceClassName(Arguments args) {
969 NoHandleAllocation ha;
970 ASSERT(args.length() == 2);
971
972 CONVERT_CHECKED(JSFunction, fun, args[0]);
973 CONVERT_CHECKED(String, name, args[1]);
974 fun->SetInstanceClassName(name);
975 return Heap::undefined_value();
976}
977
978
979static Object* Runtime_FunctionSetLength(Arguments args) {
980 NoHandleAllocation ha;
981 ASSERT(args.length() == 2);
982
983 CONVERT_CHECKED(JSFunction, fun, args[0]);
984 CONVERT_CHECKED(Smi, length, args[1]);
985 fun->shared()->set_length(length->value());
986 return length;
987}
988
989
990static Object* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000991 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992 ASSERT(args.length() == 2);
993
994 CONVERT_CHECKED(JSFunction, fun, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000995 Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL);
996 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 return args[0]; // return TOS
998}
999
1000
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001001static Object* Runtime_FunctionIsAPIFunction(Arguments args) {
1002 NoHandleAllocation ha;
1003 ASSERT(args.length() == 1);
1004
1005 CONVERT_CHECKED(JSFunction, f, args[0]);
1006 // The function_data field of the shared function info is used exclusively by
1007 // the API.
1008 return !f->shared()->function_data()->IsUndefined() ? Heap::true_value()
1009 : Heap::false_value();
1010}
1011
1012
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001013static Object* Runtime_SetCode(Arguments args) {
1014 HandleScope scope;
1015 ASSERT(args.length() == 2);
1016
1017 CONVERT_CHECKED(JSFunction, raw_target, args[0]);
1018 Handle<JSFunction> target(raw_target);
1019 Handle<Object> code = args.at<Object>(1);
1020
1021 Handle<Context> context(target->context());
1022
1023 if (!code->IsNull()) {
1024 RUNTIME_ASSERT(code->IsJSFunction());
1025 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
1026 SetExpectedNofProperties(target, fun->shared()->expected_nof_properties());
1027 if (!fun->is_compiled() && !CompileLazy(fun, KEEP_EXCEPTION)) {
1028 return Failure::Exception();
1029 }
1030 // Set the code, formal parameter count, and the length of the target
1031 // function.
1032 target->set_code(fun->code());
1033 target->shared()->set_length(fun->shared()->length());
1034 target->shared()->set_formal_parameter_count(
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001035 fun->shared()->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001036 // Set the source code of the target function to undefined.
1037 // SetCode is only used for built-in constructors like String,
1038 // Array, and Object, and some web code
1039 // doesn't like seeing source code for constructors.
1040 target->shared()->set_script(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001041 context = Handle<Context>(fun->context());
1042
1043 // Make sure we get a fresh copy of the literal vector to avoid
1044 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001045 int number_of_literals = fun->NumberOfLiterals();
1046 Handle<FixedArray> literals =
1047 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001049 // Insert the object, regexp and array functions in the literals
1050 // array prefix. These are the functions that will be used when
1051 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001052 literals->set(JSFunction::kLiteralGlobalContextIndex,
1053 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001054 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001055 target->set_literals(*literals, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001056 }
1057
1058 target->set_context(*context);
1059 return *target;
1060}
1061
1062
1063static Object* CharCodeAt(String* subject, Object* index) {
1064 uint32_t i = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001065 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001066 // Flatten the string. If someone wants to get a char at an index
1067 // in a cons string, it is likely that more indices will be
1068 // accessed.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001069 subject->TryFlattenIfNotFlat(StringShape(subject));
ager@chromium.org870a0b62008-11-04 11:43:05 +00001070 StringShape shape(subject);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001071 if (i >= static_cast<uint32_t>(subject->length(shape))) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001072 return Heap::nan_value();
1073 }
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001074 return Smi::FromInt(subject->Get(shape, i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075}
1076
1077
1078static Object* Runtime_StringCharCodeAt(Arguments args) {
1079 NoHandleAllocation ha;
1080 ASSERT(args.length() == 2);
1081
1082 CONVERT_CHECKED(String, subject, args[0]);
1083 Object* index = args[1];
1084 return CharCodeAt(subject, index);
1085}
1086
1087
1088static Object* Runtime_CharFromCode(Arguments args) {
1089 NoHandleAllocation ha;
1090 ASSERT(args.length() == 1);
1091 uint32_t code;
1092 if (Array::IndexFromObject(args[0], &code)) {
1093 if (code <= 0xffff) {
1094 return Heap::LookupSingleCharacterStringFromCode(code);
1095 }
1096 }
1097 return Heap::empty_string();
1098}
1099
1100
ager@chromium.org7c537e22008-10-16 08:43:32 +00001101// Cap on the maximal shift in the Boyer-Moore implementation. By setting a
1102// limit, we can fix the size of tables.
1103static const int kBMMaxShift = 0xff;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001104// Reduce alphabet to this size.
1105static const int kBMAlphabetSize = 0x100;
1106// For patterns below this length, the skip length of Boyer-Moore is too short
1107// to compensate for the algorithmic overhead compared to simple brute force.
1108static const int kBMMinPatternLength = 5;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001109
ager@chromium.org7c537e22008-10-16 08:43:32 +00001110// Holds the two buffers used by Boyer-Moore string search's Good Suffix
1111// shift. Only allows the last kBMMaxShift characters of the needle
1112// to be indexed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001113class BMGoodSuffixBuffers {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001114 public:
1115 BMGoodSuffixBuffers() {}
1116 inline void init(int needle_length) {
1117 ASSERT(needle_length > 1);
1118 int start = needle_length < kBMMaxShift ? 0 : needle_length - kBMMaxShift;
1119 int len = needle_length - start;
1120 biased_suffixes_ = suffixes_ - start;
1121 biased_good_suffix_shift_ = good_suffix_shift_ - start;
1122 for (int i = 0; i <= len; i++) {
1123 good_suffix_shift_[i] = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001124 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001125 }
1126 inline int& suffix(int index) {
1127 ASSERT(biased_suffixes_ + index >= suffixes_);
1128 return biased_suffixes_[index];
1129 }
1130 inline int& shift(int index) {
1131 ASSERT(biased_good_suffix_shift_ + index >= good_suffix_shift_);
1132 return biased_good_suffix_shift_[index];
1133 }
1134 private:
1135 int suffixes_[kBMMaxShift + 1];
1136 int good_suffix_shift_[kBMMaxShift + 1];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001137 int* biased_suffixes_;
1138 int* biased_good_suffix_shift_;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001139 DISALLOW_COPY_AND_ASSIGN(BMGoodSuffixBuffers);
1140};
1141
1142// buffers reused by BoyerMoore
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001143static int bad_char_occurrence[kBMAlphabetSize];
ager@chromium.org7c537e22008-10-16 08:43:32 +00001144static BMGoodSuffixBuffers bmgs_buffers;
1145
1146// Compute the bad-char table for Boyer-Moore in the static buffer.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001147template <typename pchar>
1148static void BoyerMoorePopulateBadCharTable(Vector<const pchar> pattern,
1149 int start) {
1150 // Run forwards to populate bad_char_table, so that *last* instance
1151 // of character equivalence class is the one registered.
1152 // Notice: Doesn't include the last character.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001153 int table_size = (sizeof(pchar) == 1) ? String::kMaxAsciiCharCode + 1
1154 : kBMAlphabetSize;
1155 if (start == 0) { // All patterns less than kBMMaxShift in length.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001156 memset(bad_char_occurrence, -1, table_size * sizeof(*bad_char_occurrence));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001157 } else {
1158 for (int i = 0; i < table_size; i++) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001159 bad_char_occurrence[i] = start - 1;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001160 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001161 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001162 for (int i = start; i < pattern.length() - 1; i++) {
1163 pchar c = pattern[i];
1164 int bucket = (sizeof(pchar) ==1) ? c : c % kBMAlphabetSize;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001165 bad_char_occurrence[bucket] = i;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001166 }
1167}
1168
1169template <typename pchar>
1170static void BoyerMoorePopulateGoodSuffixTable(Vector<const pchar> pattern,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001171 int start) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001172 int m = pattern.length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001173 int len = m - start;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001174 // Compute Good Suffix tables.
1175 bmgs_buffers.init(m);
1176
1177 bmgs_buffers.shift(m-1) = 1;
1178 bmgs_buffers.suffix(m) = m + 1;
1179 pchar last_char = pattern[m - 1];
1180 int suffix = m + 1;
1181 for (int i = m; i > start;) {
1182 for (pchar c = pattern[i - 1]; suffix <= m && c != pattern[suffix - 1];) {
1183 if (bmgs_buffers.shift(suffix) == len) {
1184 bmgs_buffers.shift(suffix) = suffix - i;
1185 }
1186 suffix = bmgs_buffers.suffix(suffix);
1187 }
1188 i--;
1189 suffix--;
1190 bmgs_buffers.suffix(i) = suffix;
1191 if (suffix == m) {
1192 // No suffix to extend, so we check against last_char only.
1193 while (i > start && pattern[i - 1] != last_char) {
1194 if (bmgs_buffers.shift(m) == len) {
1195 bmgs_buffers.shift(m) = m - i;
1196 }
1197 i--;
1198 bmgs_buffers.suffix(i) = m;
1199 }
1200 if (i > start) {
1201 i--;
1202 suffix--;
1203 bmgs_buffers.suffix(i) = suffix;
1204 }
1205 }
1206 }
1207 if (suffix < m) {
1208 for (int i = start; i <= m; i++) {
1209 if (bmgs_buffers.shift(i) == len) {
1210 bmgs_buffers.shift(i) = suffix - start;
1211 }
1212 if (i == suffix) {
1213 suffix = bmgs_buffers.suffix(suffix);
1214 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 }
1216 }
1217}
1218
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001219template <typename schar, typename pchar>
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001220static inline int CharOccurrence(int char_code) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001221 if (sizeof(schar) == 1) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001222 return bad_char_occurrence[char_code];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001223 }
1224 if (sizeof(pchar) == 1) {
1225 if (char_code > String::kMaxAsciiCharCode) {
1226 return -1;
1227 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001228 return bad_char_occurrence[char_code];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001229 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001230 return bad_char_occurrence[char_code % kBMAlphabetSize];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001231}
1232
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001233// Restricted simplified Boyer-Moore string matching.
1234// Uses only the bad-shift table of Boyer-Moore and only uses it
1235// for the character compared to the last character of the needle.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001236template <typename schar, typename pchar>
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001237static int BoyerMooreHorsepool(Vector<const schar> subject,
1238 Vector<const pchar> pattern,
1239 int start_index,
1240 bool* complete) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001241 int n = subject.length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001242 int m = pattern.length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00001243 // Only preprocess at most kBMMaxShift last characters of pattern.
1244 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245
ager@chromium.org7c537e22008-10-16 08:43:32 +00001246 BoyerMoorePopulateBadCharTable(pattern, start);
1247
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001248 int badness = -m; // How bad we are doing without a good-suffix table.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001249 int idx; // No matches found prior to this index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001250 pchar last_char = pattern[m - 1];
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001251 int last_char_shift = m - 1 - CharOccurrence<schar, pchar>(last_char);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001252 // Perform search
1253 for (idx = start_index; idx <= n - m;) {
1254 int j = m - 1;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001255 int c;
1256 while (last_char != (c = subject[idx + j])) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001257 int bc_occ = CharOccurrence<schar, pchar>(c);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001258 int shift = j - bc_occ;
1259 idx += shift;
1260 badness += 1 - shift; // at most zero, so badness cannot increase.
1261 if (idx > n - m) {
1262 *complete = true;
1263 return -1;
1264 }
1265 }
1266 j--;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001267 while (j >= 0 && pattern[j] == (subject[idx + j])) j--;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001268 if (j < 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001269 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001270 return idx;
1271 } else {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001272 idx += last_char_shift;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001273 // Badness increases by the number of characters we have
1274 // checked, and decreases by the number of characters we
1275 // can skip by shifting. It's a measure of how we are doing
1276 // compared to reading each character exactly once.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001277 badness += (m - j) - last_char_shift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001278 if (badness > 0) {
1279 *complete = false;
1280 return idx;
1281 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001282 }
1283 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001284 *complete = true;
1285 return -1;
1286}
ager@chromium.org7c537e22008-10-16 08:43:32 +00001287
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001288
1289template <typename schar, typename pchar>
1290static int BoyerMooreIndexOf(Vector<const schar> subject,
1291 Vector<const pchar> pattern,
1292 int idx) {
1293 int n = subject.length();
1294 int m = pattern.length();
1295 // Only preprocess at most kBMMaxShift last characters of pattern.
1296 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
1297
1298 // Build the Good Suffix table and continue searching.
1299 BoyerMoorePopulateGoodSuffixTable(pattern, start);
1300 pchar last_char = pattern[m - 1];
1301 // Continue search from i.
1302 do {
1303 int j = m - 1;
1304 schar c;
1305 while (last_char != (c = subject[idx + j])) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001306 int shift = j - CharOccurrence<schar, pchar>(c);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001307 idx += shift;
1308 if (idx > n - m) {
1309 return -1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001310 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001311 }
1312 while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--;
1313 if (j < 0) {
1314 return idx;
1315 } else if (j < start) {
1316 // we have matched more than our tables allow us to be smart about.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001317 // Fall back on BMH shift.
1318 idx += m - 1 - CharOccurrence<schar, pchar>(last_char);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001319 } else {
1320 int gs_shift = bmgs_buffers.shift(j + 1); // Good suffix shift.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001321 int bc_occ = CharOccurrence<schar, pchar>(c);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001322 int shift = j - bc_occ; // Bad-char shift.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001323 if (gs_shift > shift) {
1324 shift = gs_shift;
1325 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001326 idx += shift;
1327 }
1328 } while (idx <= n - m);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001329
1330 return -1;
1331}
1332
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001333
1334template <typename schar>
ager@chromium.org7c537e22008-10-16 08:43:32 +00001335static int SingleCharIndexOf(Vector<const schar> string,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001336 schar pattern_char,
ager@chromium.org7c537e22008-10-16 08:43:32 +00001337 int start_index) {
1338 for (int i = start_index, n = string.length(); i < n; i++) {
1339 if (pattern_char == string[i]) {
1340 return i;
1341 }
1342 }
1343 return -1;
1344}
1345
1346// Trivial string search for shorter strings.
1347// On return, if "complete" is set to true, the return value is the
1348// final result of searching for the patter in the subject.
1349// If "complete" is set to false, the return value is the index where
1350// further checking should start, i.e., it's guaranteed that the pattern
1351// does not occur at a position prior to the returned index.
1352template <typename pchar, typename schar>
1353static int SimpleIndexOf(Vector<const schar> subject,
1354 Vector<const pchar> pattern,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001355 int idx,
1356 bool* complete) {
1357 // Badness is a count of how much work we have done. When we have
1358 // done enough work we decide it's probably worth switching to a better
1359 // algorithm.
1360 int badness = -10 - (pattern.length() << 2);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001361 // We know our pattern is at least 2 characters, we cache the first so
1362 // the common case of the first character not matching is faster.
1363 pchar pattern_first_char = pattern[0];
1364
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001365 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) {
1366 badness++;
1367 if (badness > 0) {
1368 *complete = false;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001369 return i;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001370 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001371 if (subject[i] != pattern_first_char) continue;
1372 int j = 1;
1373 do {
1374 if (pattern[j] != subject[i+j]) {
1375 break;
1376 }
1377 j++;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001378 } while (j < pattern.length());
1379 if (j == pattern.length()) {
1380 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001381 return i;
1382 }
1383 badness += j;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001384 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001385 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001386 return -1;
1387}
1388
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001389// Simple indexOf that never bails out. For short patterns only.
1390template <typename pchar, typename schar>
1391static int SimpleIndexOf(Vector<const schar> subject,
1392 Vector<const pchar> pattern,
1393 int idx) {
1394 pchar pattern_first_char = pattern[0];
1395 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) {
1396 if (subject[i] != pattern_first_char) continue;
1397 int j = 1;
1398 do {
1399 if (pattern[j] != subject[i+j]) {
1400 break;
1401 }
1402 j++;
1403 } while (j < pattern.length());
1404 if (j == pattern.length()) {
1405 return i;
1406 }
1407 }
1408 return -1;
1409}
1410
1411
1412// Dispatch to different algorithms.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001413template <typename schar, typename pchar>
1414static int StringMatchStrategy(Vector<const schar> sub,
1415 Vector<const pchar> pat,
1416 int start_index) {
1417 ASSERT(pat.length() > 1);
1418
1419 // We have an ASCII haystack and a non-ASCII needle. Check if there
1420 // really is a non-ASCII character in the needle and bail out if there
1421 // is.
1422 if (sizeof(pchar) > 1 && sizeof(schar) == 1) {
1423 for (int i = 0; i < pat.length(); i++) {
1424 uc16 c = pat[i];
1425 if (c > String::kMaxAsciiCharCode) {
1426 return -1;
1427 }
1428 }
1429 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001430 if (pat.length() < kBMMinPatternLength) {
1431 // We don't believe fancy searching can ever be more efficient.
1432 // The max shift of Boyer-Moore on a pattern of this length does
1433 // not compensate for the overhead.
1434 return SimpleIndexOf(sub, pat, start_index);
1435 }
1436 // Try algorithms in order of increasing setup cost and expected performance.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001437 bool complete;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001438 int idx = SimpleIndexOf(sub, pat, start_index, &complete);
1439 if (complete) return idx;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001440 idx = BoyerMooreHorsepool(sub, pat, idx, &complete);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001441 if (complete) return idx;
1442 return BoyerMooreIndexOf(sub, pat, idx);
1443}
1444
1445// Perform string match of pattern on subject, starting at start index.
1446// Caller must ensure that 0 <= start_index <= sub->length(),
1447// and should check that pat->length() + start_index <= sub->length()
1448int Runtime::StringMatch(Handle<String> sub,
1449 Handle<String> pat,
1450 int start_index) {
1451 ASSERT(0 <= start_index);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001452 StringShape sub_shape(*sub);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001453 ASSERT(start_index <= sub->length(sub_shape));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001454
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001455 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001456 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001457
ager@chromium.org870a0b62008-11-04 11:43:05 +00001458 int subject_length = sub->length(sub_shape);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001459 if (start_index + pattern_length > subject_length) return -1;
1460
ager@chromium.org870a0b62008-11-04 11:43:05 +00001461 if (!sub->IsFlat(sub_shape)) {
1462 FlattenString(sub);
1463 sub_shape = StringShape(*sub);
1464 }
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001465 StringShape pat_shape(*pat);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466 // Searching for one specific character is common. For one
ager@chromium.org7c537e22008-10-16 08:43:32 +00001467 // character patterns linear search is necessary, so any smart
1468 // algorithm is unnecessary overhead.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001469 if (pattern_length == 1) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001470 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
ager@chromium.org870a0b62008-11-04 11:43:05 +00001471 if (sub_shape.IsAsciiRepresentation()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001472 uc16 pchar = pat->Get(pat_shape, 0);
1473 if (pchar > String::kMaxAsciiCharCode) {
1474 return -1;
1475 }
1476 Vector<const char> ascii_vector =
1477 sub->ToAsciiVector().SubVector(start_index, subject_length);
1478 const void* pos = memchr(ascii_vector.start(),
1479 static_cast<const char>(pchar),
1480 static_cast<size_t>(ascii_vector.length()));
1481 if (pos == NULL) {
1482 return -1;
1483 }
1484 return reinterpret_cast<const char*>(pos) - ascii_vector.start()
1485 + start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001486 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00001487 return SingleCharIndexOf(sub->ToUC16Vector(),
1488 pat->Get(pat_shape, 0),
1489 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490 }
1491
ager@chromium.org870a0b62008-11-04 11:43:05 +00001492 if (!pat->IsFlat(pat_shape)) {
1493 FlattenString(pat);
1494 pat_shape = StringShape(*pat);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001495 sub_shape = StringShape(*sub);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001496 }
ager@chromium.org236ad962008-09-25 09:45:57 +00001497
ager@chromium.org7c537e22008-10-16 08:43:32 +00001498 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
1499 // dispatch on type of strings
ager@chromium.org870a0b62008-11-04 11:43:05 +00001500 if (pat_shape.IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001501 Vector<const char> pat_vector = pat->ToAsciiVector();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001502 if (sub_shape.IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001503 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00001504 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001505 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00001506 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001507 Vector<const uc16> pat_vector = pat->ToUC16Vector();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001508 if (sub_shape.IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001509 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001511 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001512}
1513
1514
1515static Object* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001516 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001517 ASSERT(args.length() == 3);
1518
ager@chromium.org7c537e22008-10-16 08:43:32 +00001519 CONVERT_ARG_CHECKED(String, sub, 0);
1520 CONVERT_ARG_CHECKED(String, pat, 1);
1521
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001522 Object* index = args[2];
1523 uint32_t start_index;
1524 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
1525
ager@chromium.org870a0b62008-11-04 11:43:05 +00001526 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001527 int position = Runtime::StringMatch(sub, pat, start_index);
1528 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529}
1530
1531
1532static Object* Runtime_StringLastIndexOf(Arguments args) {
1533 NoHandleAllocation ha;
1534 ASSERT(args.length() == 3);
1535
1536 CONVERT_CHECKED(String, sub, args[0]);
1537 CONVERT_CHECKED(String, pat, args[1]);
1538 Object* index = args[2];
1539
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001540 sub->TryFlattenIfNotFlat(StringShape(sub));
1541 pat->TryFlattenIfNotFlat(StringShape(pat));
ager@chromium.org870a0b62008-11-04 11:43:05 +00001542
1543 StringShape sub_shape(sub);
1544 StringShape pat_shape(pat);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001545
1546 uint32_t start_index;
1547 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
1548
ager@chromium.org870a0b62008-11-04 11:43:05 +00001549 uint32_t pattern_length = pat->length(pat_shape);
1550 uint32_t sub_length = sub->length(sub_shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001551
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001552 if (start_index + pattern_length > sub_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001553 start_index = sub_length - pattern_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001554 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555
1556 for (int i = start_index; i >= 0; i--) {
1557 bool found = true;
1558 for (uint32_t j = 0; j < pattern_length; j++) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001559 if (sub->Get(sub_shape, i + j) != pat->Get(pat_shape, j)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 found = false;
1561 break;
1562 }
1563 }
1564 if (found) return Smi::FromInt(i);
1565 }
1566
1567 return Smi::FromInt(-1);
1568}
1569
1570
1571static Object* Runtime_StringLocaleCompare(Arguments args) {
1572 NoHandleAllocation ha;
1573 ASSERT(args.length() == 2);
1574
1575 CONVERT_CHECKED(String, str1, args[0]);
1576 CONVERT_CHECKED(String, str2, args[1]);
1577
1578 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.org870a0b62008-11-04 11:43:05 +00001579 StringShape shape1(str1);
1580 StringShape shape2(str2);
1581 int str1_length = str1->length(shape1);
1582 int str2_length = str2->length(shape2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583
1584 // Decide trivial cases without flattening.
1585 if (str1_length == 0) {
1586 if (str2_length == 0) return Smi::FromInt(0); // Equal.
1587 return Smi::FromInt(-str2_length);
1588 } else {
1589 if (str2_length == 0) return Smi::FromInt(str1_length);
1590 }
1591
1592 int end = str1_length < str2_length ? str1_length : str2_length;
1593
1594 // No need to flatten if we are going to find the answer on the first
1595 // character. At this point we know there is at least one character
1596 // in each string, due to the trivial case handling above.
ager@chromium.org870a0b62008-11-04 11:43:05 +00001597 int d = str1->Get(shape1, 0) - str2->Get(shape2, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598 if (d != 0) return Smi::FromInt(d);
1599
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001600 str1->TryFlattenIfNotFlat(shape1); // Shapes are no longer valid now!
1601 str2->TryFlattenIfNotFlat(shape2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602
1603 static StringInputBuffer buf1;
1604 static StringInputBuffer buf2;
1605
1606 buf1.Reset(str1);
1607 buf2.Reset(str2);
1608
1609 for (int i = 0; i < end; i++) {
1610 uint16_t char1 = buf1.GetNext();
1611 uint16_t char2 = buf2.GetNext();
1612 if (char1 != char2) return Smi::FromInt(char1 - char2);
1613 }
1614
1615 return Smi::FromInt(str1_length - str2_length);
1616}
1617
1618
1619static Object* Runtime_StringSlice(Arguments args) {
1620 NoHandleAllocation ha;
1621 ASSERT(args.length() == 3);
1622
1623 CONVERT_CHECKED(String, value, args[0]);
1624 CONVERT_DOUBLE_CHECKED(from_number, args[1]);
1625 CONVERT_DOUBLE_CHECKED(to_number, args[2]);
1626
1627 int start = FastD2I(from_number);
1628 int end = FastD2I(to_number);
1629
1630 RUNTIME_ASSERT(end >= start);
1631 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001632 RUNTIME_ASSERT(end <= value->length());
1633 return value->Slice(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001634}
1635
1636
1637static Object* Runtime_NumberToRadixString(Arguments args) {
1638 NoHandleAllocation ha;
1639 ASSERT(args.length() == 2);
1640
1641 CONVERT_DOUBLE_CHECKED(value, args[0]);
1642 if (isnan(value)) {
1643 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1644 }
1645 if (isinf(value)) {
1646 if (value < 0) {
1647 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1648 }
1649 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1650 }
1651 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
1652 int radix = FastD2I(radix_number);
1653 RUNTIME_ASSERT(2 <= radix && radix <= 36);
1654 char* str = DoubleToRadixCString(value, radix);
1655 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
1656 DeleteArray(str);
1657 return result;
1658}
1659
1660
1661static Object* Runtime_NumberToFixed(Arguments args) {
1662 NoHandleAllocation ha;
1663 ASSERT(args.length() == 2);
1664
1665 CONVERT_DOUBLE_CHECKED(value, args[0]);
1666 if (isnan(value)) {
1667 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1668 }
1669 if (isinf(value)) {
1670 if (value < 0) {
1671 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1672 }
1673 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1674 }
1675 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1676 int f = FastD2I(f_number);
1677 RUNTIME_ASSERT(f >= 0);
1678 char* str = DoubleToFixedCString(value, f);
1679 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1680 DeleteArray(str);
1681 return res;
1682}
1683
1684
1685static Object* Runtime_NumberToExponential(Arguments args) {
1686 NoHandleAllocation ha;
1687 ASSERT(args.length() == 2);
1688
1689 CONVERT_DOUBLE_CHECKED(value, args[0]);
1690 if (isnan(value)) {
1691 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1692 }
1693 if (isinf(value)) {
1694 if (value < 0) {
1695 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1696 }
1697 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1698 }
1699 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1700 int f = FastD2I(f_number);
1701 RUNTIME_ASSERT(f >= -1 && f <= 20);
1702 char* str = DoubleToExponentialCString(value, f);
1703 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1704 DeleteArray(str);
1705 return res;
1706}
1707
1708
1709static Object* Runtime_NumberToPrecision(Arguments args) {
1710 NoHandleAllocation ha;
1711 ASSERT(args.length() == 2);
1712
1713 CONVERT_DOUBLE_CHECKED(value, args[0]);
1714 if (isnan(value)) {
1715 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1716 }
1717 if (isinf(value)) {
1718 if (value < 0) {
1719 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1720 }
1721 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1722 }
1723 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1724 int f = FastD2I(f_number);
1725 RUNTIME_ASSERT(f >= 1 && f <= 21);
1726 char* str = DoubleToPrecisionCString(value, f);
1727 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1728 DeleteArray(str);
1729 return res;
1730}
1731
1732
1733// Returns a single character string where first character equals
1734// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001735static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001736 StringShape shape(*string);
1737 if (index < static_cast<uint32_t>(string->length(shape))) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001738 string->TryFlattenIfNotFlat(shape); // Invalidates shape!
ager@chromium.org870a0b62008-11-04 11:43:05 +00001739 return LookupSingleCharacterStringFromCode(
1740 string->Get(StringShape(*string), index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001741 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001742 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001743}
1744
1745
1746Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
1747 // Handle [] indexing on Strings
1748 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001749 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
1750 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001751 }
1752
1753 // Handle [] indexing on String objects
1754 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001755 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
1756 Handle<Object> result =
1757 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
1758 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001759 }
1760
1761 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001762 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001763 return prototype->GetElement(index);
1764 }
1765
1766 return object->GetElement(index);
1767}
1768
1769
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001770Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) {
1771 HandleScope scope;
1772
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001773 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001774 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001775 Handle<Object> error =
1776 Factory::NewTypeError("non_object_property_load",
1777 HandleVector(args, 2));
1778 return Top::Throw(*error);
1779 }
1780
1781 // Check if the given key is an array index.
1782 uint32_t index;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001783 if (Array::IndexFromObject(*key, &index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001784 return GetElementOrCharAt(object, index);
1785 }
1786
1787 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001788 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001789 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001790 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001791 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001792 bool has_pending_exception = false;
1793 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001794 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001795 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001796 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001797 }
1798
ager@chromium.org32912102009-01-16 10:38:43 +00001799 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001800 // the element if so.
1801 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001802 return GetElementOrCharAt(object, index);
1803 } else {
1804 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001805 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001806 }
1807}
1808
1809
1810static Object* Runtime_GetProperty(Arguments args) {
1811 NoHandleAllocation ha;
1812 ASSERT(args.length() == 2);
1813
1814 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001815 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001816
1817 return Runtime::GetObjectProperty(object, key);
1818}
1819
1820
ager@chromium.org7c537e22008-10-16 08:43:32 +00001821
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001822// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001823static Object* Runtime_KeyedGetProperty(Arguments args) {
1824 NoHandleAllocation ha;
1825 ASSERT(args.length() == 2);
1826
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001827 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00001828 // itself.
1829 //
1830 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00001831 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00001832 // global proxy object never has properties. This is the case
1833 // because the global proxy object forwards everything to its hidden
1834 // prototype including local lookups.
1835 //
1836 // Additionally, we need to make sure that we do not cache results
1837 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001838 if (args[0]->IsJSObject() &&
1839 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00001840 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001841 args[1]->IsString()) {
1842 JSObject* receiver = JSObject::cast(args[0]);
1843 String* key = String::cast(args[1]);
1844 if (receiver->HasFastProperties()) {
1845 // Attempt to use lookup cache.
1846 Object* obj = Heap::GetKeyedLookupCache();
1847 if (obj->IsFailure()) return obj;
1848 LookupCache* cache = LookupCache::cast(obj);
1849 Map* receiver_map = receiver->map();
1850 int offset = cache->Lookup(receiver_map, key);
1851 if (offset != LookupCache::kNotFound) {
1852 Object* value = receiver->FastPropertyAt(offset);
1853 return value->IsTheHole() ? Heap::undefined_value() : value;
1854 }
1855 // Lookup cache miss. Perform lookup and update the cache if
1856 // appropriate.
1857 LookupResult result;
1858 receiver->LocalLookup(key, &result);
1859 if (result.IsProperty() && result.IsLoaded() && result.type() == FIELD) {
1860 int offset = result.GetFieldIndex();
1861 Object* obj = cache->Put(receiver_map, key, offset);
1862 if (obj->IsFailure()) return obj;
1863 Heap::SetKeyedLookupCache(LookupCache::cast(obj));
1864 Object* value = receiver->FastPropertyAt(offset);
1865 return value->IsTheHole() ? Heap::undefined_value() : value;
1866 }
1867 } else {
1868 // Attempt dictionary lookup.
1869 Dictionary* dictionary = receiver->property_dictionary();
1870 int entry = dictionary->FindStringEntry(key);
1871 if ((entry != DescriptorArray::kNotFound) &&
1872 (dictionary->DetailsAt(entry).type() == NORMAL)) {
1873 return dictionary->ValueAt(entry);
1874 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001875 }
1876 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001877
1878 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001879 return Runtime::GetObjectProperty(args.at<Object>(0),
1880 args.at<Object>(1));
1881}
1882
1883
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001884Object* Runtime::SetObjectProperty(Handle<Object> object,
1885 Handle<Object> key,
1886 Handle<Object> value,
1887 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001888 HandleScope scope;
1889
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001891 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001892 Handle<Object> error =
1893 Factory::NewTypeError("non_object_property_store",
1894 HandleVector(args, 2));
1895 return Top::Throw(*error);
1896 }
1897
1898 // If the object isn't a JavaScript object, we ignore the store.
1899 if (!object->IsJSObject()) return *value;
1900
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001901 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
1902
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001903 // Check if the given key is an array index.
1904 uint32_t index;
1905 if (Array::IndexFromObject(*key, &index)) {
1906 ASSERT(attr == NONE);
1907
1908 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
1909 // of a string using [] notation. We need to support this too in
1910 // JavaScript.
1911 // In the case of a String object we just need to redirect the assignment to
1912 // the underlying string if the index is in range. Since the underlying
1913 // string does nothing with the assignment then we can ignore such
1914 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001915 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001916 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001917 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001918
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001919 Handle<Object> result = SetElement(js_object, index, value);
1920 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001921 return *value;
1922 }
1923
1924 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001925 Handle<Object> result;
1926 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001927 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001928 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001930 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001931 key_string->TryFlattenIfNotFlat(StringShape(*key_string));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001932 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001933 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001934 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001935 return *value;
1936 }
1937
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001938 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001939 bool has_pending_exception = false;
1940 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
1941 if (has_pending_exception) return Failure::Exception();
1942 Handle<String> name = Handle<String>::cast(converted);
1943
1944 if (name->AsArrayIndex(&index)) {
1945 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001946 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001947 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001948 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001949 }
1950}
1951
1952
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953static Object* Runtime_SetProperty(Arguments args) {
1954 NoHandleAllocation ha;
1955 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
1956
1957 Handle<Object> object = args.at<Object>(0);
1958 Handle<Object> key = args.at<Object>(1);
1959 Handle<Object> value = args.at<Object>(2);
1960
1961 // Compute attributes.
1962 PropertyAttributes attributes = NONE;
1963 if (args.length() == 4) {
1964 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001965 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001966 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001967 RUNTIME_ASSERT(
1968 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1969 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001970 }
1971 return Runtime::SetObjectProperty(object, key, value, attributes);
1972}
1973
1974
1975// Set a local property, even if it is READ_ONLY. If the property does not
1976// exist, it will be added with attributes NONE.
1977static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
1978 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001979 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001980 CONVERT_CHECKED(JSObject, object, args[0]);
1981 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001982 // Compute attributes.
1983 PropertyAttributes attributes = NONE;
1984 if (args.length() == 4) {
1985 CONVERT_CHECKED(Smi, value_obj, args[3]);
1986 int unchecked_value = value_obj->value();
1987 // Only attribute bits should be set.
1988 RUNTIME_ASSERT(
1989 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1990 attributes = static_cast<PropertyAttributes>(unchecked_value);
1991 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001992
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001993 return object->
1994 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001995}
1996
1997
1998static Object* Runtime_DeleteProperty(Arguments args) {
1999 NoHandleAllocation ha;
2000 ASSERT(args.length() == 2);
2001
2002 CONVERT_CHECKED(JSObject, object, args[0]);
2003 CONVERT_CHECKED(String, key, args[1]);
2004 return object->DeleteProperty(key);
2005}
2006
2007
2008static Object* Runtime_HasLocalProperty(Arguments args) {
2009 NoHandleAllocation ha;
2010 ASSERT(args.length() == 2);
2011 CONVERT_CHECKED(String, key, args[1]);
2012
2013 // Only JS objects can have properties.
2014 if (args[0]->IsJSObject()) {
2015 JSObject* object = JSObject::cast(args[0]);
2016 if (object->HasLocalProperty(key)) return Heap::true_value();
2017 } else if (args[0]->IsString()) {
2018 // Well, there is one exception: Handle [] on strings.
2019 uint32_t index;
2020 if (key->AsArrayIndex(&index)) {
2021 String* string = String::cast(args[0]);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002022 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002023 return Heap::true_value();
2024 }
2025 }
2026 return Heap::false_value();
2027}
2028
2029
2030static Object* Runtime_HasProperty(Arguments args) {
2031 NoHandleAllocation na;
2032 ASSERT(args.length() == 2);
2033
2034 // Only JS objects can have properties.
2035 if (args[0]->IsJSObject()) {
2036 JSObject* object = JSObject::cast(args[0]);
2037 CONVERT_CHECKED(String, key, args[1]);
2038 if (object->HasProperty(key)) return Heap::true_value();
2039 }
2040 return Heap::false_value();
2041}
2042
2043
2044static Object* Runtime_HasElement(Arguments args) {
2045 NoHandleAllocation na;
2046 ASSERT(args.length() == 2);
2047
2048 // Only JS objects can have elements.
2049 if (args[0]->IsJSObject()) {
2050 JSObject* object = JSObject::cast(args[0]);
2051 CONVERT_CHECKED(Smi, index_obj, args[1]);
2052 uint32_t index = index_obj->value();
2053 if (object->HasElement(index)) return Heap::true_value();
2054 }
2055 return Heap::false_value();
2056}
2057
2058
2059static Object* Runtime_IsPropertyEnumerable(Arguments args) {
2060 NoHandleAllocation ha;
2061 ASSERT(args.length() == 2);
2062
2063 CONVERT_CHECKED(JSObject, object, args[0]);
2064 CONVERT_CHECKED(String, key, args[1]);
2065
2066 uint32_t index;
2067 if (key->AsArrayIndex(&index)) {
2068 return Heap::ToBoolean(object->HasElement(index));
2069 }
2070
ager@chromium.org870a0b62008-11-04 11:43:05 +00002071 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
2072 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002073}
2074
2075
2076static Object* Runtime_GetPropertyNames(Arguments args) {
2077 HandleScope scope;
2078 ASSERT(args.length() == 1);
2079
2080 CONVERT_CHECKED(JSObject, raw_object, args[0]);
2081 Handle<JSObject> object(raw_object);
2082 return *GetKeysFor(object);
2083}
2084
2085
2086// Returns either a FixedArray as Runtime_GetPropertyNames,
2087// or, if the given object has an enum cache that contains
2088// all enumerable properties of the object and its prototypes
2089// have none, the map of the object. This is used to speed up
2090// the check for deletions during a for-in.
2091static Object* Runtime_GetPropertyNamesFast(Arguments args) {
2092 ASSERT(args.length() == 1);
2093
2094 CONVERT_CHECKED(JSObject, raw_object, args[0]);
2095
2096 if (raw_object->IsSimpleEnum()) return raw_object->map();
2097
2098 HandleScope scope;
2099 Handle<JSObject> object(raw_object);
2100 Handle<FixedArray> content = GetKeysInFixedArrayFor(object);
2101
2102 // Test again, since cache may have been built by preceding call.
2103 if (object->IsSimpleEnum()) return object->map();
2104
2105 return *content;
2106}
2107
2108
2109static Object* Runtime_GetArgumentsProperty(Arguments args) {
2110 NoHandleAllocation ha;
2111 ASSERT(args.length() == 1);
2112
2113 // Compute the frame holding the arguments.
2114 JavaScriptFrameIterator it;
2115 it.AdvanceToArgumentsFrame();
2116 JavaScriptFrame* frame = it.frame();
2117
2118 // Get the actual number of provided arguments.
2119 const uint32_t n = frame->GetProvidedParametersCount();
2120
2121 // Try to convert the key to an index. If successful and within
2122 // index return the the argument from the frame.
2123 uint32_t index;
2124 if (Array::IndexFromObject(args[0], &index) && index < n) {
2125 return frame->GetParameter(index);
2126 }
2127
2128 // Convert the key to a string.
2129 HandleScope scope;
2130 bool exception = false;
2131 Handle<Object> converted =
2132 Execution::ToString(args.at<Object>(0), &exception);
2133 if (exception) return Failure::Exception();
2134 Handle<String> key = Handle<String>::cast(converted);
2135
2136 // Try to convert the string key into an array index.
2137 if (key->AsArrayIndex(&index)) {
2138 if (index < n) {
2139 return frame->GetParameter(index);
2140 } else {
2141 return Top::initial_object_prototype()->GetElement(index);
2142 }
2143 }
2144
2145 // Handle special arguments properties.
2146 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
2147 if (key->Equals(Heap::callee_symbol())) return frame->function();
2148
2149 // Lookup in the initial Object.prototype object.
2150 return Top::initial_object_prototype()->GetProperty(*key);
2151}
2152
2153
2154static Object* Runtime_ToBool(Arguments args) {
2155 NoHandleAllocation ha;
2156 ASSERT(args.length() == 1);
2157
2158 return args[0]->ToBoolean();
2159}
2160
2161
2162// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
2163// Possible optimizations: put the type string into the oddballs.
2164static Object* Runtime_Typeof(Arguments args) {
2165 NoHandleAllocation ha;
2166
2167 Object* obj = args[0];
2168 if (obj->IsNumber()) return Heap::number_symbol();
2169 HeapObject* heap_obj = HeapObject::cast(obj);
2170
2171 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002172 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173
2174 InstanceType instance_type = heap_obj->map()->instance_type();
2175 if (instance_type < FIRST_NONSTRING_TYPE) {
2176 return Heap::string_symbol();
2177 }
2178
2179 switch (instance_type) {
2180 case ODDBALL_TYPE:
2181 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
2182 return Heap::boolean_symbol();
2183 }
2184 if (heap_obj->IsNull()) {
2185 return Heap::object_symbol();
2186 }
2187 ASSERT(heap_obj->IsUndefined());
2188 return Heap::undefined_symbol();
2189 case JS_FUNCTION_TYPE:
2190 return Heap::function_symbol();
2191 default:
2192 // For any kind of object not handled above, the spec rule for
2193 // host objects gives that it is okay to return "object"
2194 return Heap::object_symbol();
2195 }
2196}
2197
2198
2199static Object* Runtime_StringToNumber(Arguments args) {
2200 NoHandleAllocation ha;
2201 ASSERT(args.length() == 1);
2202 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002203 subject->TryFlattenIfNotFlat(StringShape(subject));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002204 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
2205}
2206
2207
2208static Object* Runtime_StringFromCharCodeArray(Arguments args) {
2209 NoHandleAllocation ha;
2210 ASSERT(args.length() == 1);
2211
2212 CONVERT_CHECKED(JSArray, codes, args[0]);
2213 int length = Smi::cast(codes->length())->value();
2214
2215 // Check if the string can be ASCII.
2216 int i;
2217 for (i = 0; i < length; i++) {
2218 Object* element = codes->GetElement(i);
2219 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
2220 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
2221 break;
2222 }
2223
2224 Object* object = NULL;
2225 if (i == length) { // The string is ASCII.
2226 object = Heap::AllocateRawAsciiString(length);
2227 } else { // The string is not ASCII.
2228 object = Heap::AllocateRawTwoByteString(length);
2229 }
2230
2231 if (object->IsFailure()) return object;
2232 String* result = String::cast(object);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002233 StringShape result_shape(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002234 for (int i = 0; i < length; i++) {
2235 Object* element = codes->GetElement(i);
2236 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002237 result->Set(result_shape, i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002238 }
2239 return result;
2240}
2241
2242
2243// kNotEscaped is generated by the following:
2244//
2245// #!/bin/perl
2246// for (my $i = 0; $i < 256; $i++) {
2247// print "\n" if $i % 16 == 0;
2248// my $c = chr($i);
2249// my $escaped = 1;
2250// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
2251// print $escaped ? "0, " : "1, ";
2252// }
2253
2254
2255static bool IsNotEscaped(uint16_t character) {
2256 // Only for 8 bit characters, the rest are always escaped (in a different way)
2257 ASSERT(character < 256);
2258 static const char kNotEscaped[256] = {
2259 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2260 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2261 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
2262 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
2263 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2264 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
2265 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2266 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
2267 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2268 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2269 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2270 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2271 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2272 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2273 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2274 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2275 };
2276 return kNotEscaped[character] != 0;
2277}
2278
2279
2280static Object* Runtime_URIEscape(Arguments args) {
2281 const char hex_chars[] = "0123456789ABCDEF";
2282 NoHandleAllocation ha;
2283 ASSERT(args.length() == 1);
2284 CONVERT_CHECKED(String, source, args[0]);
2285
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002286 source->TryFlattenIfNotFlat(StringShape(source));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002287
2288 int escaped_length = 0;
2289 int length = source->length();
2290 {
2291 Access<StringInputBuffer> buffer(&string_input_buffer);
2292 buffer->Reset(source);
2293 while (buffer->has_more()) {
2294 uint16_t character = buffer->GetNext();
2295 if (character >= 256) {
2296 escaped_length += 6;
2297 } else if (IsNotEscaped(character)) {
2298 escaped_length++;
2299 } else {
2300 escaped_length += 3;
2301 }
2302 // We don't allow strings that are longer than Smi range.
2303 if (!Smi::IsValid(escaped_length)) {
2304 Top::context()->mark_out_of_memory();
2305 return Failure::OutOfMemoryException();
2306 }
2307 }
2308 }
2309 // No length change implies no change. Return original string if no change.
2310 if (escaped_length == length) {
2311 return source;
2312 }
2313 Object* o = Heap::AllocateRawAsciiString(escaped_length);
2314 if (o->IsFailure()) return o;
2315 String* destination = String::cast(o);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002316 StringShape dshape(destination);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002317 int dest_position = 0;
2318
2319 Access<StringInputBuffer> buffer(&string_input_buffer);
2320 buffer->Rewind();
2321 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00002322 uint16_t chr = buffer->GetNext();
2323 if (chr >= 256) {
2324 destination->Set(dshape, dest_position, '%');
2325 destination->Set(dshape, dest_position+1, 'u');
2326 destination->Set(dshape, dest_position+2, hex_chars[chr >> 12]);
2327 destination->Set(dshape, dest_position+3, hex_chars[(chr >> 8) & 0xf]);
2328 destination->Set(dshape, dest_position+4, hex_chars[(chr >> 4) & 0xf]);
2329 destination->Set(dshape, dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002330 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002331 } else if (IsNotEscaped(chr)) {
2332 destination->Set(dshape, dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002333 dest_position++;
2334 } else {
ager@chromium.org870a0b62008-11-04 11:43:05 +00002335 destination->Set(dshape, dest_position, '%');
2336 destination->Set(dshape, dest_position+1, hex_chars[chr >> 4]);
2337 destination->Set(dshape, dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002338 dest_position += 3;
2339 }
2340 }
2341 return destination;
2342}
2343
2344
2345static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
2346 static const signed char kHexValue['g'] = {
2347 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2348 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2349 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2350 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
2351 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2352 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2353 -1, 10, 11, 12, 13, 14, 15 };
2354
2355 if (character1 > 'f') return -1;
2356 int hi = kHexValue[character1];
2357 if (hi == -1) return -1;
2358 if (character2 > 'f') return -1;
2359 int lo = kHexValue[character2];
2360 if (lo == -1) return -1;
2361 return (hi << 4) + lo;
2362}
2363
2364
ager@chromium.org870a0b62008-11-04 11:43:05 +00002365static inline int Unescape(String* source,
2366 StringShape shape,
2367 int i,
2368 int length,
2369 int* step) {
2370 uint16_t character = source->Get(shape, i);
2371 int32_t hi = 0;
2372 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002373 if (character == '%' &&
2374 i <= length - 6 &&
ager@chromium.org870a0b62008-11-04 11:43:05 +00002375 source->Get(shape, i + 1) == 'u' &&
2376 (hi = TwoDigitHex(source->Get(shape, i + 2),
2377 source->Get(shape, i + 3))) != -1 &&
2378 (lo = TwoDigitHex(source->Get(shape, i + 4),
2379 source->Get(shape, i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002380 *step = 6;
2381 return (hi << 8) + lo;
2382 } else if (character == '%' &&
2383 i <= length - 3 &&
ager@chromium.org870a0b62008-11-04 11:43:05 +00002384 (lo = TwoDigitHex(source->Get(shape, i + 1),
2385 source->Get(shape, i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002386 *step = 3;
2387 return lo;
2388 } else {
2389 *step = 1;
2390 return character;
2391 }
2392}
2393
2394
2395static Object* Runtime_URIUnescape(Arguments args) {
2396 NoHandleAllocation ha;
2397 ASSERT(args.length() == 1);
2398 CONVERT_CHECKED(String, source, args[0]);
2399
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002400 source->TryFlattenIfNotFlat(StringShape(source));
ager@chromium.org870a0b62008-11-04 11:43:05 +00002401 StringShape source_shape(source);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002402
2403 bool ascii = true;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002404 int length = source->length(source_shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002405
2406 int unescaped_length = 0;
2407 for (int i = 0; i < length; unescaped_length++) {
2408 int step;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002409 if (Unescape(source,
2410 source_shape,
2411 i,
2412 length,
2413 &step) >
2414 String::kMaxAsciiCharCode)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002415 ascii = false;
2416 i += step;
2417 }
2418
2419 // No length change implies no change. Return original string if no change.
2420 if (unescaped_length == length)
2421 return source;
2422
2423 Object* o = ascii ?
2424 Heap::AllocateRawAsciiString(unescaped_length) :
2425 Heap::AllocateRawTwoByteString(unescaped_length);
2426 if (o->IsFailure()) return o;
2427 String* destination = String::cast(o);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002428 StringShape destination_shape(destination);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002429
2430 int dest_position = 0;
2431 for (int i = 0; i < length; dest_position++) {
2432 int step;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002433 destination->Set(destination_shape,
2434 dest_position,
2435 Unescape(source, source_shape, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002436 i += step;
2437 }
2438 return destination;
2439}
2440
2441
2442static Object* Runtime_StringParseInt(Arguments args) {
2443 NoHandleAllocation ha;
2444
2445 CONVERT_CHECKED(String, s, args[0]);
2446 CONVERT_DOUBLE_CHECKED(n, args[1]);
2447 int radix = FastD2I(n);
2448
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002449 s->TryFlattenIfNotFlat(StringShape(s));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002450
ager@chromium.org870a0b62008-11-04 11:43:05 +00002451 StringShape shape(s);
2452
2453 int len = s->length(shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002454 int i;
2455
2456 // Skip leading white space.
ager@chromium.org870a0b62008-11-04 11:43:05 +00002457 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(shape, i)); i++) ;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002458 if (i == len) return Heap::nan_value();
2459
2460 // Compute the sign (default to +).
2461 int sign = 1;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002462 if (s->Get(shape, i) == '-') {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002463 sign = -1;
2464 i++;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002465 } else if (s->Get(shape, i) == '+') {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002466 i++;
2467 }
2468
2469 // Compute the radix if 0.
2470 if (radix == 0) {
2471 radix = 10;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002472 if (i < len && s->Get(shape, i) == '0') {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002473 radix = 8;
2474 if (i + 1 < len) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00002475 int c = s->Get(shape, i + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002476 if (c == 'x' || c == 'X') {
2477 radix = 16;
2478 i += 2;
2479 }
2480 }
2481 }
2482 } else if (radix == 16) {
2483 // Allow 0x or 0X prefix if radix is 16.
ager@chromium.org870a0b62008-11-04 11:43:05 +00002484 if (i + 1 < len && s->Get(shape, i) == '0') {
2485 int c = s->Get(shape, i + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002486 if (c == 'x' || c == 'X') i += 2;
2487 }
2488 }
2489
2490 RUNTIME_ASSERT(2 <= radix && radix <= 36);
2491 double value;
2492 int end_index = StringToInt(s, i, radix, &value);
2493 if (end_index != i) {
2494 return Heap::NumberFromDouble(sign * value);
2495 }
2496 return Heap::nan_value();
2497}
2498
2499
2500static Object* Runtime_StringParseFloat(Arguments args) {
2501 NoHandleAllocation ha;
2502 CONVERT_CHECKED(String, str, args[0]);
2503
2504 // ECMA-262 section 15.1.2.3, empty string is NaN
2505 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
2506
2507 // Create a number object from the value.
2508 return Heap::NumberFromDouble(value);
2509}
2510
2511
2512static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
2513static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
2514
2515
2516template <class Converter>
2517static Object* ConvertCase(Arguments args,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002518 unibrow::Mapping<Converter, 128>* mapping) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002519 NoHandleAllocation ha;
2520
2521 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002522 s->TryFlattenIfNotFlat(StringShape(s));
ager@chromium.org870a0b62008-11-04 11:43:05 +00002523 StringShape shape(s);
2524
2525 int raw_string_length = s->length(shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002526 // Assume that the string is not empty; we need this assumption later
2527 if (raw_string_length == 0) return s;
2528 int length = raw_string_length;
2529
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002530
2531 // We try this twice, once with the assumption that the result is
2532 // no longer than the input and, if that assumption breaks, again
2533 // with the exact length. This is implemented using a goto back
2534 // to this label if we discover that the assumption doesn't hold.
2535 // I apologize sincerely for this and will give a vaffel-is to
mads.s.ager31e71382008-08-13 09:32:07 +00002536 // the first person who can implement it in a nicer way.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002537 try_convert:
2538
2539 // Allocate the resulting string.
2540 //
2541 // NOTE: This assumes that the upper/lower case of an ascii
2542 // character is also ascii. This is currently the case, but it
2543 // might break in the future if we implement more context and locale
2544 // dependent upper/lower conversions.
ager@chromium.org870a0b62008-11-04 11:43:05 +00002545 Object* o = shape.IsAsciiRepresentation()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002546 ? Heap::AllocateRawAsciiString(length)
2547 : Heap::AllocateRawTwoByteString(length);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002548 if (o->IsFailure()) return o;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002549 String* result = String::cast(o);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002550 StringShape result_shape(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002551 bool has_changed_character = false;
2552
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002553 // Convert all characters to upper case, assuming that they will fit
2554 // in the buffer
2555 Access<StringInputBuffer> buffer(&string_input_buffer);
2556 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002557 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002558 int i = 0;
2559 // We can assume that the string is not empty
2560 uc32 current = buffer->GetNext();
2561 while (i < length) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002562 bool has_next = buffer->has_more();
2563 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002564 int char_length = mapping->get(current, next, chars);
2565 if (char_length == 0) {
2566 // The case conversion of this character is the character itself.
ager@chromium.org870a0b62008-11-04 11:43:05 +00002567 result->Set(result_shape, i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002568 i++;
2569 } else if (char_length == 1) {
2570 // Common case: converting the letter resulted in one character.
2571 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002572 result->Set(result_shape, i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002573 has_changed_character = true;
2574 i++;
2575 } else if (length == raw_string_length) {
2576 // We've assumed that the result would be as long as the
2577 // input but here is a character that converts to several
2578 // characters. No matter, we calculate the exact length
2579 // of the result and try the whole thing again.
2580 //
2581 // Note that this leaves room for optimization. We could just
2582 // memcpy what we already have to the result string. Also,
2583 // the result string is the last object allocated we could
2584 // "realloc" it and probably, in the vast majority of cases,
2585 // extend the existing string to be able to hold the full
2586 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002587 int next_length = 0;
2588 if (has_next) {
2589 next_length = mapping->get(next, 0, chars);
2590 if (next_length == 0) next_length = 1;
2591 }
2592 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002593 while (buffer->has_more()) {
2594 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002595 // NOTE: we use 0 as the next character here because, while
2596 // the next character may affect what a character converts to,
2597 // it does not in any case affect the length of what it convert
2598 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002599 int char_length = mapping->get(current, 0, chars);
2600 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002601 current_length += char_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002602 }
2603 length = current_length;
2604 goto try_convert;
2605 } else {
2606 for (int j = 0; j < char_length; j++) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00002607 result->Set(result_shape, i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002608 i++;
2609 }
2610 has_changed_character = true;
2611 }
2612 current = next;
2613 }
2614 if (has_changed_character) {
2615 return result;
2616 } else {
2617 // If we didn't actually change anything in doing the conversion
2618 // we simple return the result and let the converted string
2619 // become garbage; there is no reason to keep two identical strings
2620 // alive.
2621 return s;
2622 }
2623}
2624
2625
2626static Object* Runtime_StringToLowerCase(Arguments args) {
2627 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping);
2628}
2629
2630
2631static Object* Runtime_StringToUpperCase(Arguments args) {
2632 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping);
2633}
2634
2635
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002636static Object* Runtime_NumberToString(Arguments args) {
2637 NoHandleAllocation ha;
2638 ASSERT(args.length() == 1);
2639
2640 Object* number = args[0];
2641 RUNTIME_ASSERT(number->IsNumber());
2642
2643 Object* cached = Heap::GetNumberStringCache(number);
2644 if (cached != Heap::undefined_value()) {
2645 return cached;
2646 }
2647
2648 char arr[100];
2649 Vector<char> buffer(arr, ARRAY_SIZE(arr));
2650 const char* str;
2651 if (number->IsSmi()) {
2652 int num = Smi::cast(number)->value();
2653 str = IntToCString(num, buffer);
2654 } else {
2655 double num = HeapNumber::cast(number)->value();
2656 str = DoubleToCString(num, buffer);
2657 }
2658 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
2659
2660 if (!result->IsFailure()) {
2661 Heap::SetNumberStringCache(number, String::cast(result));
2662 }
2663 return result;
2664}
2665
2666
2667static Object* Runtime_NumberToInteger(Arguments args) {
2668 NoHandleAllocation ha;
2669 ASSERT(args.length() == 1);
2670
2671 Object* obj = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002672 if (obj->IsSmi()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002673 CONVERT_DOUBLE_CHECKED(number, obj);
2674 return Heap::NumberFromDouble(DoubleToInteger(number));
2675}
2676
2677
2678static Object* Runtime_NumberToJSUint32(Arguments args) {
2679 NoHandleAllocation ha;
2680 ASSERT(args.length() == 1);
2681
2682 Object* obj = args[0];
2683 if (obj->IsSmi() && Smi::cast(obj)->value() >= 0) return obj;
2684 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, obj);
2685 return Heap::NumberFromUint32(number);
2686}
2687
2688
2689static Object* Runtime_NumberToJSInt32(Arguments args) {
2690 NoHandleAllocation ha;
2691 ASSERT(args.length() == 1);
2692
2693 Object* obj = args[0];
2694 if (obj->IsSmi()) return obj;
2695 CONVERT_DOUBLE_CHECKED(number, obj);
2696 return Heap::NumberFromInt32(DoubleToInt32(number));
2697}
2698
2699
ager@chromium.org870a0b62008-11-04 11:43:05 +00002700// Converts a Number to a Smi, if possible. Returns NaN if the number is not
2701// a small integer.
2702static Object* Runtime_NumberToSmi(Arguments args) {
2703 NoHandleAllocation ha;
2704 ASSERT(args.length() == 1);
2705
2706 Object* obj = args[0];
2707 if (obj->IsSmi()) {
2708 return obj;
2709 }
2710 if (obj->IsHeapNumber()) {
2711 double value = HeapNumber::cast(obj)->value();
2712 int int_value = FastD2I(value);
2713 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
2714 return Smi::FromInt(int_value);
2715 }
2716 }
2717 return Heap::nan_value();
2718}
2719
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002720static Object* Runtime_NumberAdd(Arguments args) {
2721 NoHandleAllocation ha;
2722 ASSERT(args.length() == 2);
2723
2724 CONVERT_DOUBLE_CHECKED(x, args[0]);
2725 CONVERT_DOUBLE_CHECKED(y, args[1]);
2726 return Heap::AllocateHeapNumber(x + y);
2727}
2728
2729
2730static Object* Runtime_NumberSub(Arguments args) {
2731 NoHandleAllocation ha;
2732 ASSERT(args.length() == 2);
2733
2734 CONVERT_DOUBLE_CHECKED(x, args[0]);
2735 CONVERT_DOUBLE_CHECKED(y, args[1]);
2736 return Heap::AllocateHeapNumber(x - y);
2737}
2738
2739
2740static Object* Runtime_NumberMul(Arguments args) {
2741 NoHandleAllocation ha;
2742 ASSERT(args.length() == 2);
2743
2744 CONVERT_DOUBLE_CHECKED(x, args[0]);
2745 CONVERT_DOUBLE_CHECKED(y, args[1]);
2746 return Heap::AllocateHeapNumber(x * y);
2747}
2748
2749
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002750static Object* Runtime_NumberUnaryMinus(Arguments args) {
2751 NoHandleAllocation ha;
2752 ASSERT(args.length() == 1);
2753
2754 CONVERT_DOUBLE_CHECKED(x, args[0]);
2755 return Heap::AllocateHeapNumber(-x);
2756}
2757
2758
2759static Object* Runtime_NumberDiv(Arguments args) {
2760 NoHandleAllocation ha;
2761 ASSERT(args.length() == 2);
2762
2763 CONVERT_DOUBLE_CHECKED(x, args[0]);
2764 CONVERT_DOUBLE_CHECKED(y, args[1]);
2765 return Heap::NewNumberFromDouble(x / y);
2766}
2767
2768
2769static Object* Runtime_NumberMod(Arguments args) {
2770 NoHandleAllocation ha;
2771 ASSERT(args.length() == 2);
2772
2773 CONVERT_DOUBLE_CHECKED(x, args[0]);
2774 CONVERT_DOUBLE_CHECKED(y, args[1]);
2775
2776#ifdef WIN32
2777 // Workaround MS fmod bugs. ECMA-262 says:
2778 // dividend is finite and divisor is an infinity => result equals dividend
2779 // dividend is a zero and divisor is nonzero finite => result equals dividend
2780 if (!(isfinite(x) && (!isfinite(y) && !isnan(y))) &&
2781 !(x == 0 && (y != 0 && isfinite(y))))
2782#endif
2783 x = fmod(x, y);
2784 // NewNumberFromDouble may return a Smi instead of a Number object
2785 return Heap::NewNumberFromDouble(x);
2786}
2787
2788
2789static Object* Runtime_StringAdd(Arguments args) {
2790 NoHandleAllocation ha;
2791 ASSERT(args.length() == 2);
2792
2793 CONVERT_CHECKED(String, str1, args[0]);
2794 CONVERT_CHECKED(String, str2, args[1]);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002795 int len1 = str1->length();
2796 int len2 = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002797 if (len1 == 0) return str2;
2798 if (len2 == 0) return str1;
2799 int length_sum = len1 + len2;
2800 // Make sure that an out of memory exception is thrown if the length
2801 // of the new cons string is too large to fit in a Smi.
2802 if (length_sum > Smi::kMaxValue || length_sum < 0) {
2803 Top::context()->mark_out_of_memory();
2804 return Failure::OutOfMemoryException();
2805 }
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002806 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002807}
2808
2809
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002810template<typename sinkchar>
2811static inline void StringBuilderConcatHelper(String* special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00002812 StringShape special_shape,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002813 sinkchar* sink,
2814 FixedArray* fixed_array,
2815 int array_length) {
2816 int position = 0;
2817 for (int i = 0; i < array_length; i++) {
2818 Object* element = fixed_array->get(i);
2819 if (element->IsSmi()) {
2820 int len = Smi::cast(element)->value();
2821 int pos = len >> 11;
2822 len &= 0x7ff;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002823 String::WriteToFlat(special,
2824 special_shape,
2825 sink + position,
2826 pos,
2827 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002828 position += len;
2829 } else {
2830 String* string = String::cast(element);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002831 StringShape shape(string);
2832 int element_length = string->length(shape);
2833 String::WriteToFlat(string, shape, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002834 position += element_length;
2835 }
2836 }
2837}
2838
2839
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002840static Object* Runtime_StringBuilderConcat(Arguments args) {
2841 NoHandleAllocation ha;
2842 ASSERT(args.length() == 2);
2843 CONVERT_CHECKED(JSArray, array, args[0]);
2844 CONVERT_CHECKED(String, special, args[1]);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002845 StringShape special_shape(special);
2846 int special_length = special->length(special_shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002847 Object* smi_array_length = array->length();
2848 if (!smi_array_length->IsSmi()) {
2849 Top::context()->mark_out_of_memory();
2850 return Failure::OutOfMemoryException();
2851 }
2852 int array_length = Smi::cast(smi_array_length)->value();
2853 if (!array->HasFastElements()) {
2854 return Top::Throw(Heap::illegal_argument_symbol());
2855 }
2856 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002857 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002858 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002859 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002860
2861 if (array_length == 0) {
2862 return Heap::empty_string();
2863 } else if (array_length == 1) {
2864 Object* first = fixed_array->get(0);
2865 if (first->IsString()) return first;
2866 }
2867
ager@chromium.org870a0b62008-11-04 11:43:05 +00002868 bool ascii = special_shape.IsAsciiRepresentation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002869 int position = 0;
2870 for (int i = 0; i < array_length; i++) {
2871 Object* elt = fixed_array->get(i);
2872 if (elt->IsSmi()) {
2873 int len = Smi::cast(elt)->value();
2874 int pos = len >> 11;
2875 len &= 0x7ff;
2876 if (pos + len > special_length) {
2877 return Top::Throw(Heap::illegal_argument_symbol());
2878 }
2879 position += len;
2880 } else if (elt->IsString()) {
2881 String* element = String::cast(elt);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002882 StringShape element_shape(element);
2883 int element_length = element->length(element_shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002884 if (!Smi::IsValid(element_length + position)) {
2885 Top::context()->mark_out_of_memory();
2886 return Failure::OutOfMemoryException();
2887 }
2888 position += element_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002889 if (ascii && !element_shape.IsAsciiRepresentation()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002890 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002891 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002892 } else {
2893 return Top::Throw(Heap::illegal_argument_symbol());
2894 }
2895 }
2896
2897 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002898 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002899
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002900 if (ascii) {
2901 object = Heap::AllocateRawAsciiString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002902 if (object->IsFailure()) return object;
2903 SeqAsciiString* answer = SeqAsciiString::cast(object);
2904 StringBuilderConcatHelper(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00002905 special_shape,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002906 answer->GetChars(),
2907 fixed_array,
2908 array_length);
2909 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002910 } else {
2911 object = Heap::AllocateRawTwoByteString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002912 if (object->IsFailure()) return object;
2913 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
2914 StringBuilderConcatHelper(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00002915 special_shape,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002916 answer->GetChars(),
2917 fixed_array,
2918 array_length);
2919 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002920 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002921}
2922
2923
2924static Object* Runtime_NumberOr(Arguments args) {
2925 NoHandleAllocation ha;
2926 ASSERT(args.length() == 2);
2927
2928 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2929 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2930 return Heap::NumberFromInt32(x | y);
2931}
2932
2933
2934static Object* Runtime_NumberAnd(Arguments args) {
2935 NoHandleAllocation ha;
2936 ASSERT(args.length() == 2);
2937
2938 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2939 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2940 return Heap::NumberFromInt32(x & y);
2941}
2942
2943
2944static Object* Runtime_NumberXor(Arguments args) {
2945 NoHandleAllocation ha;
2946 ASSERT(args.length() == 2);
2947
2948 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2949 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2950 return Heap::NumberFromInt32(x ^ y);
2951}
2952
2953
2954static Object* Runtime_NumberNot(Arguments args) {
2955 NoHandleAllocation ha;
2956 ASSERT(args.length() == 1);
2957
2958 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2959 return Heap::NumberFromInt32(~x);
2960}
2961
2962
2963static Object* Runtime_NumberShl(Arguments args) {
2964 NoHandleAllocation ha;
2965 ASSERT(args.length() == 2);
2966
2967 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2968 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2969 return Heap::NumberFromInt32(x << (y & 0x1f));
2970}
2971
2972
2973static Object* Runtime_NumberShr(Arguments args) {
2974 NoHandleAllocation ha;
2975 ASSERT(args.length() == 2);
2976
2977 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
2978 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2979 return Heap::NumberFromUint32(x >> (y & 0x1f));
2980}
2981
2982
2983static Object* Runtime_NumberSar(Arguments args) {
2984 NoHandleAllocation ha;
2985 ASSERT(args.length() == 2);
2986
2987 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2988 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2989 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
2990}
2991
2992
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002993static Object* Runtime_NumberEquals(Arguments args) {
2994 NoHandleAllocation ha;
2995 ASSERT(args.length() == 2);
2996
2997 CONVERT_DOUBLE_CHECKED(x, args[0]);
2998 CONVERT_DOUBLE_CHECKED(y, args[1]);
2999 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
3000 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
3001 if (x == y) return Smi::FromInt(EQUAL);
3002 Object* result;
3003 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
3004 result = Smi::FromInt(EQUAL);
3005 } else {
3006 result = Smi::FromInt(NOT_EQUAL);
3007 }
3008 return result;
3009}
3010
3011
3012static Object* Runtime_StringEquals(Arguments args) {
3013 NoHandleAllocation ha;
3014 ASSERT(args.length() == 2);
3015
3016 CONVERT_CHECKED(String, x, args[0]);
3017 CONVERT_CHECKED(String, y, args[1]);
3018
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003019 bool not_equal = !x->Equals(y);
3020 // This is slightly convoluted because the value that signifies
3021 // equality is 0 and inequality is 1 so we have to negate the result
3022 // from String::Equals.
3023 ASSERT(not_equal == 0 || not_equal == 1);
3024 STATIC_CHECK(EQUAL == 0);
3025 STATIC_CHECK(NOT_EQUAL == 1);
3026 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003027}
3028
3029
3030static Object* Runtime_NumberCompare(Arguments args) {
3031 NoHandleAllocation ha;
3032 ASSERT(args.length() == 3);
3033
3034 CONVERT_DOUBLE_CHECKED(x, args[0]);
3035 CONVERT_DOUBLE_CHECKED(y, args[1]);
3036 if (isnan(x) || isnan(y)) return args[2];
3037 if (x == y) return Smi::FromInt(EQUAL);
3038 if (isless(x, y)) return Smi::FromInt(LESS);
3039 return Smi::FromInt(GREATER);
3040}
3041
3042
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003043// Compare two Smis as if they were converted to strings and then
3044// compared lexicographically.
3045static Object* Runtime_SmiLexicographicCompare(Arguments args) {
3046 NoHandleAllocation ha;
3047 ASSERT(args.length() == 2);
3048
3049 // Arrays for the individual characters of the two Smis. Smis are
3050 // 31 bit integers and 10 decimal digits are therefore enough.
3051 static int x_elms[10];
3052 static int y_elms[10];
3053
3054 // Extract the integer values from the Smis.
3055 CONVERT_CHECKED(Smi, x, args[0]);
3056 CONVERT_CHECKED(Smi, y, args[1]);
3057 int x_value = x->value();
3058 int y_value = y->value();
3059
3060 // If the integers are equal so are the string representations.
3061 if (x_value == y_value) return Smi::FromInt(EQUAL);
3062
3063 // If one of the integers are zero the normal integer order is the
3064 // same as the lexicographic order of the string representations.
3065 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
3066
ager@chromium.org32912102009-01-16 10:38:43 +00003067 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003068 // smallest because the char code of '-' is less than the char code
3069 // of any digit. Otherwise, we make both values positive.
3070 if (x_value < 0 || y_value < 0) {
3071 if (y_value >= 0) return Smi::FromInt(LESS);
3072 if (x_value >= 0) return Smi::FromInt(GREATER);
3073 x_value = -x_value;
3074 y_value = -y_value;
3075 }
3076
3077 // Convert the integers to arrays of their decimal digits.
3078 int x_index = 0;
3079 int y_index = 0;
3080 while (x_value > 0) {
3081 x_elms[x_index++] = x_value % 10;
3082 x_value /= 10;
3083 }
3084 while (y_value > 0) {
3085 y_elms[y_index++] = y_value % 10;
3086 y_value /= 10;
3087 }
3088
3089 // Loop through the arrays of decimal digits finding the first place
3090 // where they differ.
3091 while (--x_index >= 0 && --y_index >= 0) {
3092 int diff = x_elms[x_index] - y_elms[y_index];
3093 if (diff != 0) return Smi::FromInt(diff);
3094 }
3095
3096 // If one array is a suffix of the other array, the longest array is
3097 // the representation of the largest of the Smis in the
3098 // lexicographic ordering.
3099 return Smi::FromInt(x_index - y_index);
3100}
3101
3102
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003103static Object* Runtime_StringCompare(Arguments args) {
3104 NoHandleAllocation ha;
3105 ASSERT(args.length() == 2);
3106
3107 CONVERT_CHECKED(String, x, args[0]);
3108 CONVERT_CHECKED(String, y, args[1]);
3109
ager@chromium.org870a0b62008-11-04 11:43:05 +00003110 StringShape x_shape(x);
3111 StringShape y_shape(y);
3112
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003113 // A few fast case tests before we flatten.
3114 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.org870a0b62008-11-04 11:43:05 +00003115 if (y->length(y_shape) == 0) {
3116 if (x->length(x_shape) == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003117 return Smi::FromInt(GREATER);
ager@chromium.org870a0b62008-11-04 11:43:05 +00003118 } else if (x->length(x_shape) == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003119 return Smi::FromInt(LESS);
3120 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003121
ager@chromium.org870a0b62008-11-04 11:43:05 +00003122 int d = x->Get(x_shape, 0) - y->Get(y_shape, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003123 if (d < 0) return Smi::FromInt(LESS);
3124 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003125
ager@chromium.orgddb913d2009-01-27 10:01:48 +00003126 x->TryFlattenIfNotFlat(x_shape); // Shapes are no longer valid!
3127 y->TryFlattenIfNotFlat(y_shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003128
3129 static StringInputBuffer bufx;
3130 static StringInputBuffer bufy;
3131 bufx.Reset(x);
3132 bufy.Reset(y);
3133 while (bufx.has_more() && bufy.has_more()) {
3134 int d = bufx.GetNext() - bufy.GetNext();
3135 if (d < 0) return Smi::FromInt(LESS);
3136 else if (d > 0) return Smi::FromInt(GREATER);
3137 }
3138
3139 // x is (non-trivial) prefix of y:
3140 if (bufy.has_more()) return Smi::FromInt(LESS);
3141 // y is prefix of x:
3142 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
3143}
3144
3145
3146static Object* Runtime_Math_abs(Arguments args) {
3147 NoHandleAllocation ha;
3148 ASSERT(args.length() == 1);
3149
3150 CONVERT_DOUBLE_CHECKED(x, args[0]);
3151 return Heap::AllocateHeapNumber(fabs(x));
3152}
3153
3154
3155static Object* Runtime_Math_acos(Arguments args) {
3156 NoHandleAllocation ha;
3157 ASSERT(args.length() == 1);
3158
3159 CONVERT_DOUBLE_CHECKED(x, args[0]);
3160 return Heap::AllocateHeapNumber(acos(x));
3161}
3162
3163
3164static Object* Runtime_Math_asin(Arguments args) {
3165 NoHandleAllocation ha;
3166 ASSERT(args.length() == 1);
3167
3168 CONVERT_DOUBLE_CHECKED(x, args[0]);
3169 return Heap::AllocateHeapNumber(asin(x));
3170}
3171
3172
3173static Object* Runtime_Math_atan(Arguments args) {
3174 NoHandleAllocation ha;
3175 ASSERT(args.length() == 1);
3176
3177 CONVERT_DOUBLE_CHECKED(x, args[0]);
3178 return Heap::AllocateHeapNumber(atan(x));
3179}
3180
3181
3182static Object* Runtime_Math_atan2(Arguments args) {
3183 NoHandleAllocation ha;
3184 ASSERT(args.length() == 2);
3185
3186 CONVERT_DOUBLE_CHECKED(x, args[0]);
3187 CONVERT_DOUBLE_CHECKED(y, args[1]);
3188 double result;
3189 if (isinf(x) && isinf(y)) {
3190 // Make sure that the result in case of two infinite arguments
3191 // is a multiple of Pi / 4. The sign of the result is determined
3192 // by the first argument (x) and the sign of the second argument
3193 // determines the multiplier: one or three.
3194 static double kPiDividedBy4 = 0.78539816339744830962;
3195 int multiplier = (x < 0) ? -1 : 1;
3196 if (y < 0) multiplier *= 3;
3197 result = multiplier * kPiDividedBy4;
3198 } else {
3199 result = atan2(x, y);
3200 }
3201 return Heap::AllocateHeapNumber(result);
3202}
3203
3204
3205static Object* Runtime_Math_ceil(Arguments args) {
3206 NoHandleAllocation ha;
3207 ASSERT(args.length() == 1);
3208
3209 CONVERT_DOUBLE_CHECKED(x, args[0]);
3210 return Heap::NumberFromDouble(ceiling(x));
3211}
3212
3213
3214static Object* Runtime_Math_cos(Arguments args) {
3215 NoHandleAllocation ha;
3216 ASSERT(args.length() == 1);
3217
3218 CONVERT_DOUBLE_CHECKED(x, args[0]);
3219 return Heap::AllocateHeapNumber(cos(x));
3220}
3221
3222
3223static Object* Runtime_Math_exp(Arguments args) {
3224 NoHandleAllocation ha;
3225 ASSERT(args.length() == 1);
3226
3227 CONVERT_DOUBLE_CHECKED(x, args[0]);
3228 return Heap::AllocateHeapNumber(exp(x));
3229}
3230
3231
3232static Object* Runtime_Math_floor(Arguments args) {
3233 NoHandleAllocation ha;
3234 ASSERT(args.length() == 1);
3235
3236 CONVERT_DOUBLE_CHECKED(x, args[0]);
3237 return Heap::NumberFromDouble(floor(x));
3238}
3239
3240
3241static Object* Runtime_Math_log(Arguments args) {
3242 NoHandleAllocation ha;
3243 ASSERT(args.length() == 1);
3244
3245 CONVERT_DOUBLE_CHECKED(x, args[0]);
3246 return Heap::AllocateHeapNumber(log(x));
3247}
3248
3249
3250static Object* Runtime_Math_pow(Arguments args) {
3251 NoHandleAllocation ha;
3252 ASSERT(args.length() == 2);
3253
3254 CONVERT_DOUBLE_CHECKED(x, args[0]);
3255 CONVERT_DOUBLE_CHECKED(y, args[1]);
3256 if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
3257 return Heap::nan_value();
3258 } else if (y == 0) {
3259 return Smi::FromInt(1);
3260 } else {
3261 return Heap::AllocateHeapNumber(pow(x, y));
3262 }
3263}
3264
3265// Returns a number value with positive sign, greater than or equal to
3266// 0 but less than 1, chosen randomly.
mads.s.ager31e71382008-08-13 09:32:07 +00003267static Object* Runtime_Math_random(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003268 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003269 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003270
3271 // To get much better precision, we combine the results of two
3272 // invocations of random(). The result is computed by normalizing a
3273 // double in the range [0, RAND_MAX + 1) obtained by adding the
3274 // high-order bits in the range [0, RAND_MAX] with the low-order
3275 // bits in the range [0, 1).
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003276 double lo = static_cast<double>(random()) * (1.0 / (RAND_MAX + 1.0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003277 double hi = static_cast<double>(random());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003278 double result = (hi + lo) * (1.0 / (RAND_MAX + 1.0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003279 ASSERT(result >= 0 && result < 1);
3280 return Heap::AllocateHeapNumber(result);
3281}
3282
3283
3284static Object* Runtime_Math_round(Arguments args) {
3285 NoHandleAllocation ha;
3286 ASSERT(args.length() == 1);
3287
3288 CONVERT_DOUBLE_CHECKED(x, args[0]);
3289 if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
3290 return Heap::NumberFromDouble(floor(x + 0.5));
3291}
3292
3293
3294static Object* Runtime_Math_sin(Arguments args) {
3295 NoHandleAllocation ha;
3296 ASSERT(args.length() == 1);
3297
3298 CONVERT_DOUBLE_CHECKED(x, args[0]);
3299 return Heap::AllocateHeapNumber(sin(x));
3300}
3301
3302
3303static Object* Runtime_Math_sqrt(Arguments args) {
3304 NoHandleAllocation ha;
3305 ASSERT(args.length() == 1);
3306
3307 CONVERT_DOUBLE_CHECKED(x, args[0]);
3308 return Heap::AllocateHeapNumber(sqrt(x));
3309}
3310
3311
3312static Object* Runtime_Math_tan(Arguments args) {
3313 NoHandleAllocation ha;
3314 ASSERT(args.length() == 1);
3315
3316 CONVERT_DOUBLE_CHECKED(x, args[0]);
3317 return Heap::AllocateHeapNumber(tan(x));
3318}
3319
3320
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003321// The NewArguments function is only used when constructing the
3322// arguments array when calling non-functions from JavaScript in
3323// runtime.js:CALL_NON_FUNCTION.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003324static Object* Runtime_NewArguments(Arguments args) {
3325 NoHandleAllocation ha;
3326 ASSERT(args.length() == 1);
3327
3328 // ECMA-262, 3rd., 10.1.8, p.39
3329 CONVERT_CHECKED(JSFunction, callee, args[0]);
3330
3331 // Compute the frame holding the arguments.
3332 JavaScriptFrameIterator it;
3333 it.AdvanceToArgumentsFrame();
3334 JavaScriptFrame* frame = it.frame();
3335
3336 const int length = frame->GetProvidedParametersCount();
3337 Object* result = Heap::AllocateArgumentsObject(callee, length);
3338 if (result->IsFailure()) return result;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003339 if (length > 0) {
3340 Object* obj = Heap::AllocateFixedArray(length);
3341 if (obj->IsFailure()) return obj;
3342 FixedArray* array = FixedArray::cast(obj);
3343 ASSERT(array->length() == length);
3344 WriteBarrierMode mode = array->GetWriteBarrierMode();
3345 for (int i = 0; i < length; i++) {
3346 array->set(i, frame->GetParameter(i), mode);
3347 }
3348 JSObject::cast(result)->set_elements(array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003349 }
3350 return result;
3351}
3352
3353
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003354static Object* Runtime_NewArgumentsFast(Arguments args) {
3355 NoHandleAllocation ha;
3356 ASSERT(args.length() == 3);
3357
3358 JSFunction* callee = JSFunction::cast(args[0]);
3359 Object** parameters = reinterpret_cast<Object**>(args[1]);
3360 const int length = Smi::cast(args[2])->value();
3361
3362 Object* result = Heap::AllocateArgumentsObject(callee, length);
3363 if (result->IsFailure()) return result;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003364 ASSERT(Heap::InNewSpace(result));
3365
3366 // Allocate the elements if needed.
3367 if (length > 0) {
3368 // Allocate the fixed array.
3369 Object* obj = Heap::AllocateRawFixedArray(length);
3370 if (obj->IsFailure()) return obj;
3371 reinterpret_cast<Array*>(obj)->set_map(Heap::fixed_array_map());
3372 FixedArray* array = FixedArray::cast(obj);
3373 array->set_length(length);
3374 WriteBarrierMode mode = array->GetWriteBarrierMode();
3375 for (int i = 0; i < length; i++) {
3376 array->set(i, *--parameters, mode);
3377 }
3378 JSObject::cast(result)->set_elements(FixedArray::cast(obj),
3379 SKIP_WRITE_BARRIER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003380 }
3381 return result;
3382}
3383
3384
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003385static Object* Runtime_NewClosure(Arguments args) {
3386 HandleScope scope;
3387 ASSERT(args.length() == 2);
3388 CONVERT_ARG_CHECKED(JSFunction, boilerplate, 0);
3389 CONVERT_ARG_CHECKED(Context, context, 1);
3390
3391 Handle<JSFunction> result =
3392 Factory::NewFunctionFromBoilerplate(boilerplate, context);
3393 return *result;
3394}
3395
3396
3397static Object* Runtime_NewObject(Arguments args) {
3398 NoHandleAllocation ha;
3399 ASSERT(args.length() == 1);
3400
3401 Object* constructor = args[0];
3402 if (constructor->IsJSFunction()) {
3403 JSFunction* function = JSFunction::cast(constructor);
3404
ager@chromium.org32912102009-01-16 10:38:43 +00003405 // Handle stepping into constructors if step into is active.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003406 if (Debug::StepInActive()) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003407 HandleScope scope;
3408 Debug::HandleStepIn(Handle<JSFunction>(function), 0, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003409 }
3410
3411 if (function->has_initial_map() &&
3412 function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
3413 // The 'Function' function ignores the receiver object when
3414 // called using 'new' and creates a new JSFunction object that
3415 // is returned. The receiver object is only used for error
3416 // reporting if an error occurs when constructing the new
3417 // JSFunction. AllocateJSObject should not be used to allocate
3418 // JSFunctions since it does not properly initialize the shared
3419 // part of the function. Since the receiver is ignored anyway,
3420 // we use the global object as the receiver instead of a new
3421 // JSFunction object. This way, errors are reported the same
3422 // way whether or not 'Function' is called using 'new'.
3423 return Top::context()->global();
3424 }
3425 return Heap::AllocateJSObject(function);
3426 }
3427
3428 HandleScope scope;
3429 Handle<Object> cons(constructor);
3430 // The constructor is not a function; throw a type error.
3431 Handle<Object> type_error =
3432 Factory::NewTypeError("not_constructor", HandleVector(&cons, 1));
3433 return Top::Throw(*type_error);
3434}
3435
3436
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003437static Object* Runtime_LazyCompile(Arguments args) {
3438 HandleScope scope;
3439 ASSERT(args.length() == 1);
3440
3441 Handle<JSFunction> function = args.at<JSFunction>(0);
3442#ifdef DEBUG
3443 if (FLAG_trace_lazy) {
3444 PrintF("[lazy: ");
3445 function->shared()->name()->Print();
3446 PrintF("]\n");
3447 }
3448#endif
3449
3450 // Compile the target function.
3451 ASSERT(!function->is_compiled());
3452 if (!CompileLazy(function, KEEP_EXCEPTION)) {
3453 return Failure::Exception();
3454 }
3455
3456 return function->code();
3457}
3458
3459
3460static Object* Runtime_GetCalledFunction(Arguments args) {
3461 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00003462 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003463 StackFrameIterator it;
3464 // Get past the JS-to-C exit frame.
3465 ASSERT(it.frame()->is_exit());
3466 it.Advance();
3467 // Get past the CALL_NON_FUNCTION activation frame.
3468 ASSERT(it.frame()->is_java_script());
3469 it.Advance();
3470 // Argument adaptor frames do not copy the function; we have to skip
3471 // past them to get to the real calling frame.
3472 if (it.frame()->is_arguments_adaptor()) it.Advance();
3473 // Get the function from the top of the expression stack of the
3474 // calling frame.
3475 StandardFrame* frame = StandardFrame::cast(it.frame());
3476 int index = frame->ComputeExpressionsCount() - 1;
3477 Object* result = frame->GetExpression(index);
3478 return result;
3479}
3480
3481
3482static Object* Runtime_GetFunctionDelegate(Arguments args) {
3483 HandleScope scope;
3484 ASSERT(args.length() == 1);
3485 RUNTIME_ASSERT(!args[0]->IsJSFunction());
3486 return *Execution::GetFunctionDelegate(args.at<Object>(0));
3487}
3488
3489
3490static Object* Runtime_NewContext(Arguments args) {
3491 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00003492 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003493
kasper.lund7276f142008-07-30 08:49:36 +00003494 CONVERT_CHECKED(JSFunction, function, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003495 int length = ScopeInfo<>::NumberOfContextSlots(function->code());
3496 Object* result = Heap::AllocateFunctionContext(length, function);
3497 if (result->IsFailure()) return result;
3498
3499 Top::set_context(Context::cast(result));
3500
kasper.lund7276f142008-07-30 08:49:36 +00003501 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003502}
3503
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003504static Object* PushContextHelper(Object* object, bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003505 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003506 Object* js_object = object;
3507 if (!js_object->IsJSObject()) {
3508 js_object = js_object->ToObject();
3509 if (js_object->IsFailure()) {
3510 if (!Failure::cast(js_object)->IsInternalError()) return js_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003511 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003512 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003513 Handle<Object> result =
3514 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
3515 return Top::Throw(*result);
3516 }
3517 }
3518
3519 Object* result =
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003520 Heap::AllocateWithContext(Top::context(),
3521 JSObject::cast(js_object),
3522 is_catch_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003523 if (result->IsFailure()) return result;
3524
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003525 Context* context = Context::cast(result);
3526 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003527
kasper.lund7276f142008-07-30 08:49:36 +00003528 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003529}
3530
3531
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003532static Object* Runtime_PushContext(Arguments args) {
3533 NoHandleAllocation ha;
3534 ASSERT(args.length() == 1);
3535 return PushContextHelper(args[0], false);
3536}
3537
3538
3539static Object* Runtime_PushCatchContext(Arguments args) {
3540 NoHandleAllocation ha;
3541 ASSERT(args.length() == 1);
3542 return PushContextHelper(args[0], true);
3543}
3544
3545
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003546static Object* Runtime_LookupContext(Arguments args) {
3547 HandleScope scope;
3548 ASSERT(args.length() == 2);
3549
3550 CONVERT_ARG_CHECKED(Context, context, 0);
3551 CONVERT_ARG_CHECKED(String, name, 1);
3552
3553 int index;
3554 PropertyAttributes attributes;
3555 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003556 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003557 context->Lookup(name, flags, &index, &attributes);
3558
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003559 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003560 ASSERT(holder->IsJSObject());
3561 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003562 }
3563
3564 // No intermediate context found. Use global object by default.
3565 return Top::context()->global();
3566}
3567
3568
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003569// A mechanism to return pairs of Object*'s. This is somewhat
3570// compiler-dependent as it assumes that a 64-bit value (a long long)
3571// is returned via two registers (edx:eax on ia32). Both the ia32 and
3572// arm platform support this; it is mostly an issue of "coaxing" the
3573// compiler to do the right thing.
3574//
3575// TODO(1236026): This is a non-portable hack that should be removed.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003576typedef uint64_t ObjectPair;
3577static inline ObjectPair MakePair(Object* x, Object* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003578 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003579 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003580}
3581
3582
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003583static inline Object* Unhole(Object* x, PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003584 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
3585 USE(attributes);
3586 return x->IsTheHole() ? Heap::undefined_value() : x;
3587}
3588
3589
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003590static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
3591 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003592 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003593 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003594 JSFunction* context_extension_function =
3595 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003596 // If the holder isn't a context extension object, we just return it
3597 // as the receiver. This allows arguments objects to be used as
3598 // receivers, but only if they are put in the context scope chain
3599 // explicitly via a with-statement.
3600 Object* constructor = holder->map()->constructor();
3601 if (constructor != context_extension_function) return holder;
3602 // Fall back to using the global object as the receiver if the
3603 // property turns out to be a local variable allocated in a context
3604 // extension object - introduced via eval.
3605 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003606}
3607
3608
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003609static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003610 HandleScope scope;
3611 ASSERT(args.length() == 2);
3612
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003613 if (!args[0]->IsContext() || !args[1]->IsString()) {
3614 return MakePair(IllegalOperation(), NULL);
3615 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003617 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003618
3619 int index;
3620 PropertyAttributes attributes;
3621 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003622 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003623 context->Lookup(name, flags, &index, &attributes);
3624
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003625 // If the index is non-negative, the slot has been found in a local
3626 // variable or a parameter. Read it from the context object or the
3627 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003628 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003629 // If the "property" we were looking for is a local variable or an
3630 // argument in a context, the receiver is the global object; see
3631 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
3632 JSObject* receiver = Top::context()->global()->global_receiver();
3633 Object* value = (holder->IsContext())
3634 ? Context::cast(*holder)->get(index)
3635 : JSObject::cast(*holder)->GetElement(index);
3636 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003637 }
3638
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003639 // If the holder is found, we read the property from it.
3640 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00003641 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003642 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003643 JSObject* receiver;
3644 if (object->IsGlobalObject()) {
3645 receiver = GlobalObject::cast(object)->global_receiver();
3646 } else if (context->is_exception_holder(*holder)) {
3647 receiver = Top::context()->global()->global_receiver();
3648 } else {
3649 receiver = ComputeReceiverForNonGlobal(object);
3650 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003651 // No need to unhole the value here. This is taken care of by the
3652 // GetProperty function.
3653 Object* value = object->GetProperty(*name);
3654 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003655 }
3656
3657 if (throw_error) {
3658 // The property doesn't exist - throw exception.
3659 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003660 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 return MakePair(Top::Throw(*reference_error), NULL);
3662 } else {
3663 // The property doesn't exist - return undefined
3664 return MakePair(Heap::undefined_value(), Heap::undefined_value());
3665 }
3666}
3667
3668
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003669static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003670 return LoadContextSlotHelper(args, true);
3671}
3672
3673
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003674static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003675 return LoadContextSlotHelper(args, false);
3676}
3677
3678
3679static Object* Runtime_StoreContextSlot(Arguments args) {
3680 HandleScope scope;
3681 ASSERT(args.length() == 3);
3682
3683 Handle<Object> value(args[0]);
3684 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003685 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003686
3687 int index;
3688 PropertyAttributes attributes;
3689 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003690 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003691 context->Lookup(name, flags, &index, &attributes);
3692
3693 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003694 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003695 // Ignore if read_only variable.
3696 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003697 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698 }
3699 } else {
3700 ASSERT((attributes & READ_ONLY) == 0);
3701 Object* result =
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003702 Handle<JSObject>::cast(holder)->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003703 USE(result);
3704 ASSERT(!result->IsFailure());
3705 }
3706 return *value;
3707 }
3708
3709 // Slow case: The property is not in a FixedArray context.
3710 // It is either in an JSObject extension context or it was not found.
3711 Handle<JSObject> context_ext;
3712
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003713 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003714 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003715 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003716 } else {
3717 // The property was not found. It needs to be stored in the global context.
3718 ASSERT(attributes == ABSENT);
3719 attributes = NONE;
3720 context_ext = Handle<JSObject>(Top::context()->global());
3721 }
3722
3723 // Set the property, but ignore if read_only variable.
3724 if ((attributes & READ_ONLY) == 0) {
3725 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
3726 if (set.is_null()) {
3727 // Failure::Exception is converted to a null handle in the
3728 // handle-based methods such as SetProperty. We therefore need
3729 // to convert null handles back to exceptions.
3730 ASSERT(Top::has_pending_exception());
3731 return Failure::Exception();
3732 }
3733 }
3734 return *value;
3735}
3736
3737
3738static Object* Runtime_Throw(Arguments args) {
3739 HandleScope scope;
3740 ASSERT(args.length() == 1);
3741
3742 return Top::Throw(args[0]);
3743}
3744
3745
3746static Object* Runtime_ReThrow(Arguments args) {
3747 HandleScope scope;
3748 ASSERT(args.length() == 1);
3749
3750 return Top::ReThrow(args[0]);
3751}
3752
3753
3754static Object* Runtime_ThrowReferenceError(Arguments args) {
3755 HandleScope scope;
3756 ASSERT(args.length() == 1);
3757
3758 Handle<Object> name(args[0]);
3759 Handle<Object> reference_error =
3760 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
3761 return Top::Throw(*reference_error);
3762}
3763
3764
3765static Object* Runtime_StackOverflow(Arguments args) {
3766 NoHandleAllocation na;
3767 return Top::StackOverflow();
3768}
3769
3770
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003771static Object* Runtime_DebugBreak(Arguments args) {
3772 ASSERT(args.length() == 0);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003773 return Execution::DebugBreakHelper();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774}
3775
3776
3777static Object* Runtime_StackGuard(Arguments args) {
3778 ASSERT(args.length() == 1);
3779
3780 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00003781 if (StackGuard::IsStackOverflow()) {
3782 return Runtime_StackOverflow(args);
3783 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003784
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003785 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003786}
3787
3788
3789// NOTE: These PrintXXX functions are defined for all builds (not just
3790// DEBUG builds) because we may want to be able to trace function
3791// calls in all modes.
3792static void PrintString(String* str) {
3793 // not uncommon to have empty strings
3794 if (str->length() > 0) {
3795 SmartPointer<char> s =
3796 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
3797 PrintF("%s", *s);
3798 }
3799}
3800
3801
3802static void PrintObject(Object* obj) {
3803 if (obj->IsSmi()) {
3804 PrintF("%d", Smi::cast(obj)->value());
3805 } else if (obj->IsString() || obj->IsSymbol()) {
3806 PrintString(String::cast(obj));
3807 } else if (obj->IsNumber()) {
3808 PrintF("%g", obj->Number());
3809 } else if (obj->IsFailure()) {
3810 PrintF("<failure>");
3811 } else if (obj->IsUndefined()) {
3812 PrintF("<undefined>");
3813 } else if (obj->IsNull()) {
3814 PrintF("<null>");
3815 } else if (obj->IsTrue()) {
3816 PrintF("<true>");
3817 } else if (obj->IsFalse()) {
3818 PrintF("<false>");
3819 } else {
3820 PrintF("%p", obj);
3821 }
3822}
3823
3824
3825static int StackSize() {
3826 int n = 0;
3827 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
3828 return n;
3829}
3830
3831
3832static void PrintTransition(Object* result) {
3833 // indentation
3834 { const int nmax = 80;
3835 int n = StackSize();
3836 if (n <= nmax)
3837 PrintF("%4d:%*s", n, n, "");
3838 else
3839 PrintF("%4d:%*s", n, nmax, "...");
3840 }
3841
3842 if (result == NULL) {
3843 // constructor calls
3844 JavaScriptFrameIterator it;
3845 JavaScriptFrame* frame = it.frame();
3846 if (frame->IsConstructor()) PrintF("new ");
3847 // function name
3848 Object* fun = frame->function();
3849 if (fun->IsJSFunction()) {
3850 PrintObject(JSFunction::cast(fun)->shared()->name());
3851 } else {
3852 PrintObject(fun);
3853 }
3854 // function arguments
3855 // (we are intentionally only printing the actually
3856 // supplied parameters, not all parameters required)
3857 PrintF("(this=");
3858 PrintObject(frame->receiver());
3859 const int length = frame->GetProvidedParametersCount();
3860 for (int i = 0; i < length; i++) {
3861 PrintF(", ");
3862 PrintObject(frame->GetParameter(i));
3863 }
3864 PrintF(") {\n");
3865
3866 } else {
3867 // function result
3868 PrintF("} -> ");
3869 PrintObject(result);
3870 PrintF("\n");
3871 }
3872}
3873
3874
3875static Object* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003876 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003877 NoHandleAllocation ha;
3878 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003879 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003880}
3881
3882
3883static Object* Runtime_TraceExit(Arguments args) {
3884 NoHandleAllocation ha;
3885 PrintTransition(args[0]);
3886 return args[0]; // return TOS
3887}
3888
3889
3890static Object* Runtime_DebugPrint(Arguments args) {
3891 NoHandleAllocation ha;
3892 ASSERT(args.length() == 1);
3893
3894#ifdef DEBUG
3895 if (args[0]->IsString()) {
3896 // If we have a string, assume it's a code "marker"
3897 // and print some interesting cpu debugging info.
3898 JavaScriptFrameIterator it;
3899 JavaScriptFrame* frame = it.frame();
3900 PrintF("fp = %p, sp = %p, pp = %p: ",
3901 frame->fp(), frame->sp(), frame->pp());
3902 } else {
3903 PrintF("DebugPrint: ");
3904 }
3905 args[0]->Print();
3906#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003907 // ShortPrint is available in release mode. Print is not.
3908 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003909#endif
3910 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00003911 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003912
3913 return args[0]; // return TOS
3914}
3915
3916
3917static Object* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003918 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003919 NoHandleAllocation ha;
3920 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003921 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003922}
3923
3924
mads.s.ager31e71382008-08-13 09:32:07 +00003925static Object* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003926 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003927 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003928
3929 // According to ECMA-262, section 15.9.1, page 117, the precision of
3930 // the number in a Date object representing a particular instant in
3931 // time is milliseconds. Therefore, we floor the result of getting
3932 // the OS time.
3933 double millis = floor(OS::TimeCurrentMillis());
3934 return Heap::NumberFromDouble(millis);
3935}
3936
3937
3938static Object* Runtime_DateParseString(Arguments args) {
3939 HandleScope scope;
3940 ASSERT(args.length() == 1);
3941
3942 CONVERT_CHECKED(String, string_object, args[0]);
3943
3944 Handle<String> str(string_object);
3945 Handle<FixedArray> output = Factory::NewFixedArray(DateParser::OUTPUT_SIZE);
3946 if (DateParser::Parse(*str, *output)) {
3947 return *Factory::NewJSArrayWithElements(output);
3948 } else {
3949 return *Factory::null_value();
3950 }
3951}
3952
3953
3954static Object* Runtime_DateLocalTimezone(Arguments args) {
3955 NoHandleAllocation ha;
3956 ASSERT(args.length() == 1);
3957
3958 CONVERT_DOUBLE_CHECKED(x, args[0]);
3959 char* zone = OS::LocalTimezone(x);
3960 return Heap::AllocateStringFromUtf8(CStrVector(zone));
3961}
3962
3963
3964static Object* Runtime_DateLocalTimeOffset(Arguments args) {
3965 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003966 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003967
3968 return Heap::NumberFromDouble(OS::LocalTimeOffset());
3969}
3970
3971
3972static Object* Runtime_DateDaylightSavingsOffset(Arguments args) {
3973 NoHandleAllocation ha;
3974 ASSERT(args.length() == 1);
3975
3976 CONVERT_DOUBLE_CHECKED(x, args[0]);
3977 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
3978}
3979
3980
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003981static Object* Runtime_NumberIsFinite(Arguments args) {
3982 NoHandleAllocation ha;
3983 ASSERT(args.length() == 1);
3984
3985 CONVERT_DOUBLE_CHECKED(value, args[0]);
3986 Object* result;
3987 if (isnan(value) || (fpclassify(value) == FP_INFINITE)) {
3988 result = Heap::false_value();
3989 } else {
3990 result = Heap::true_value();
3991 }
3992 return result;
3993}
3994
3995
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003996static Object* Runtime_GlobalReceiver(Arguments args) {
3997 ASSERT(args.length() == 1);
3998 Object* global = args[0];
3999 if (!global->IsJSGlobalObject()) return Heap::null_value();
4000 return JSGlobalObject::cast(global)->global_receiver();
4001}
4002
4003
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004004static Object* Runtime_CompileString(Arguments args) {
4005 HandleScope scope;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004006 ASSERT(args.length() == 2);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004007 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org236ad962008-09-25 09:45:57 +00004008 CONVERT_ARG_CHECKED(Smi, line_offset, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004009
ager@chromium.org381abbb2009-02-25 13:23:22 +00004010 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004011 Handle<Context> context(Top::context()->global_context());
ager@chromium.org381abbb2009-02-25 13:23:22 +00004012 Handle<JSFunction> boilerplate =
4013 Compiler::CompileEval(source, context, line_offset->value(), true);
4014 if (boilerplate.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004015 Handle<JSFunction> fun =
4016 Factory::NewFunctionFromBoilerplate(boilerplate, context);
4017 return *fun;
4018}
4019
4020
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004021static Handle<JSFunction> GetBuiltinFunction(String* name) {
4022 LookupResult result;
4023 Top::global_context()->builtins()->LocalLookup(name, &result);
4024 return Handle<JSFunction>(JSFunction::cast(result.GetValue()));
4025}
4026
4027
4028static Object* CompileDirectEval(Handle<String> source) {
4029 // Compute the eval context.
4030 HandleScope scope;
4031 StackFrameLocator locator;
4032 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
4033 Handle<Context> context(Context::cast(frame->context()));
4034 bool is_global = context->IsGlobalContext();
4035
ager@chromium.org381abbb2009-02-25 13:23:22 +00004036 // Compile source string in the current context.
4037 Handle<JSFunction> boilerplate =
4038 Compiler::CompileEval(source, context, 0, is_global);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004039 if (boilerplate.is_null()) return Failure::Exception();
4040 Handle<JSFunction> fun =
4041 Factory::NewFunctionFromBoilerplate(boilerplate, context);
4042 return *fun;
4043}
4044
4045
4046static Object* Runtime_ResolvePossiblyDirectEval(Arguments args) {
4047 ASSERT(args.length() == 2);
4048
4049 HandleScope scope;
4050
4051 CONVERT_ARG_CHECKED(JSFunction, callee, 0);
4052
4053 Handle<Object> receiver;
4054
4055 // Find where the 'eval' symbol is bound. It is unaliased only if
4056 // it is bound in the global context.
4057 StackFrameLocator locator;
4058 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
4059 Handle<Context> context(Context::cast(frame->context()));
4060 int index;
4061 PropertyAttributes attributes;
4062 while (!context.is_null()) {
4063 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
4064 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00004065 // Stop search when eval is found or when the global context is
4066 // reached.
4067 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004068 if (context->is_function_context()) {
4069 context = Handle<Context>(Context::cast(context->closure()->context()));
4070 } else {
4071 context = Handle<Context>(context->previous());
4072 }
4073 }
4074
iposva@chromium.org245aa852009-02-10 00:49:54 +00004075 // If eval could not be resolved, it has been deleted and we need to
4076 // throw a reference error.
4077 if (attributes == ABSENT) {
4078 Handle<Object> name = Factory::eval_symbol();
4079 Handle<Object> reference_error =
4080 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
4081 return Top::Throw(*reference_error);
4082 }
4083
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004084 if (context->IsGlobalContext()) {
4085 // 'eval' is bound in the global context, but it may have been overwritten.
4086 // Compare it to the builtin 'GlobalEval' function to make sure.
4087 Handle<JSFunction> global_eval =
4088 GetBuiltinFunction(Heap::global_eval_symbol());
4089 if (global_eval.is_identical_to(callee)) {
4090 // A direct eval call.
4091 if (args[1]->IsString()) {
4092 CONVERT_ARG_CHECKED(String, source, 1);
4093 // A normal eval call on a string. Compile it and return the
4094 // compiled function bound in the local context.
4095 Object* compiled_source = CompileDirectEval(source);
4096 if (compiled_source->IsFailure()) return compiled_source;
4097 receiver = Handle<Object>(frame->receiver());
4098 callee = Handle<JSFunction>(JSFunction::cast(compiled_source));
4099 } else {
4100 // An eval call that is not called on a string. Global eval
4101 // deals better with this.
4102 receiver = Handle<Object>(Top::global_context()->global());
4103 }
4104 } else {
4105 // 'eval' is overwritten. Just call the function with the given arguments.
4106 receiver = Handle<Object>(Top::global_context()->global());
4107 }
4108 } else {
4109 // 'eval' is not bound in the global context. Just call the function
4110 // with the given arguments. This is not necessarily the global eval.
4111 if (receiver->IsContext()) {
4112 context = Handle<Context>::cast(receiver);
4113 receiver = Handle<Object>(context->get(index));
4114 }
4115 }
4116
4117 Handle<FixedArray> call = Factory::NewFixedArray(2);
4118 call->set(0, *callee);
4119 call->set(1, *receiver);
4120 return *call;
4121}
4122
4123
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004124static Object* Runtime_CompileScript(Arguments args) {
4125 HandleScope scope;
4126 ASSERT(args.length() == 4);
4127
4128 CONVERT_ARG_CHECKED(String, source, 0);
4129 CONVERT_ARG_CHECKED(String, script, 1);
4130 CONVERT_CHECKED(Smi, line_attrs, args[2]);
4131 int line = line_attrs->value();
4132 CONVERT_CHECKED(Smi, col_attrs, args[3]);
4133 int col = col_attrs->value();
4134 Handle<JSFunction> boilerplate =
4135 Compiler::Compile(source, script, line, col, NULL, NULL);
4136 if (boilerplate.is_null()) return Failure::Exception();
4137 Handle<JSFunction> fun =
4138 Factory::NewFunctionFromBoilerplate(boilerplate,
4139 Handle<Context>(Top::context()));
4140 return *fun;
4141}
4142
4143
4144static Object* Runtime_SetNewFunctionAttributes(Arguments args) {
4145 // This utility adjusts the property attributes for newly created Function
4146 // object ("new Function(...)") by changing the map.
4147 // All it does is changing the prototype property to enumerable
4148 // as specified in ECMA262, 15.3.5.2.
4149 HandleScope scope;
4150 ASSERT(args.length() == 1);
4151 CONVERT_ARG_CHECKED(JSFunction, func, 0);
4152 ASSERT(func->map()->instance_type() ==
4153 Top::function_instance_map()->instance_type());
4154 ASSERT(func->map()->instance_size() ==
4155 Top::function_instance_map()->instance_size());
4156 func->set_map(*Top::function_instance_map());
4157 return *func;
4158}
4159
4160
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004161// Push an array unto an array of arrays if it is not already in the
4162// array. Returns true if the element was pushed on the stack and
4163// false otherwise.
4164static Object* Runtime_PushIfAbsent(Arguments args) {
4165 ASSERT(args.length() == 2);
4166 CONVERT_CHECKED(JSArray, array, args[0]);
4167 CONVERT_CHECKED(JSArray, element, args[1]);
4168 RUNTIME_ASSERT(array->HasFastElements());
4169 int length = Smi::cast(array->length())->value();
4170 FixedArray* elements = FixedArray::cast(array->elements());
4171 for (int i = 0; i < length; i++) {
4172 if (elements->get(i) == element) return Heap::false_value();
4173 }
4174 Object* obj = array->SetFastElement(length, element);
4175 if (obj->IsFailure()) return obj;
4176 return Heap::true_value();
4177}
4178
4179
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004180/**
4181 * A simple visitor visits every element of Array's.
4182 * The backend storage can be a fixed array for fast elements case,
4183 * or a dictionary for sparse array. Since Dictionary is a subtype
4184 * of FixedArray, the class can be used by both fast and slow cases.
4185 * The second parameter of the constructor, fast_elements, specifies
4186 * whether the storage is a FixedArray or Dictionary.
4187 *
4188 * An index limit is used to deal with the situation that a result array
4189 * length overflows 32-bit non-negative integer.
4190 */
4191class ArrayConcatVisitor {
4192 public:
4193 ArrayConcatVisitor(Handle<FixedArray> storage,
4194 uint32_t index_limit,
4195 bool fast_elements) :
4196 storage_(storage), index_limit_(index_limit),
4197 fast_elements_(fast_elements), index_offset_(0) { }
4198
4199 void visit(uint32_t i, Handle<Object> elm) {
4200 uint32_t index = i + index_offset_;
4201 if (index >= index_limit_) return;
4202
4203 if (fast_elements_) {
4204 ASSERT(index < static_cast<uint32_t>(storage_->length()));
4205 storage_->set(index, *elm);
4206
4207 } else {
4208 Handle<Dictionary> dict = Handle<Dictionary>::cast(storage_);
4209 Handle<Dictionary> result =
4210 Factory::DictionaryAtNumberPut(dict, index, elm);
4211 if (!result.is_identical_to(dict))
4212 storage_ = result;
4213 }
4214 }
4215
4216 void increase_index_offset(uint32_t delta) {
4217 index_offset_ += delta;
4218 }
4219
4220 private:
4221 Handle<FixedArray> storage_;
4222 uint32_t index_limit_;
4223 bool fast_elements_;
4224 uint32_t index_offset_;
4225};
4226
4227
4228/**
4229 * A helper function that visits elements of a JSObject. Only elements
4230 * whose index between 0 and range (exclusive) are visited.
4231 *
4232 * If the third parameter, visitor, is not NULL, the visitor is called
4233 * with parameters, 'visitor_index_offset + element index' and the element.
4234 *
4235 * It returns the number of visisted elements.
4236 */
4237static uint32_t IterateElements(Handle<JSObject> receiver,
4238 uint32_t range,
4239 ArrayConcatVisitor* visitor) {
4240 uint32_t num_of_elements = 0;
4241
4242 if (receiver->HasFastElements()) {
4243 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
4244 uint32_t len = elements->length();
4245 if (range < len) len = range;
4246
4247 for (uint32_t j = 0; j < len; j++) {
4248 Handle<Object> e(elements->get(j));
4249 if (!e->IsTheHole()) {
4250 num_of_elements++;
4251 if (visitor)
4252 visitor->visit(j, e);
4253 }
4254 }
4255
4256 } else {
4257 Handle<Dictionary> dict(receiver->element_dictionary());
4258 uint32_t capacity = dict->Capacity();
4259 for (uint32_t j = 0; j < capacity; j++) {
4260 Handle<Object> k(dict->KeyAt(j));
4261 if (dict->IsKey(*k)) {
4262 ASSERT(k->IsNumber());
4263 uint32_t index = static_cast<uint32_t>(k->Number());
4264 if (index < range) {
4265 num_of_elements++;
4266 if (visitor) {
4267 visitor->visit(index,
4268 Handle<Object>(dict->ValueAt(j)));
4269 }
4270 }
4271 }
4272 }
4273 }
4274
4275 return num_of_elements;
4276}
4277
4278
4279/**
4280 * A helper function that visits elements of an Array object, and elements
4281 * on its prototypes.
4282 *
4283 * Elements on prototypes are visited first, and only elements whose indices
4284 * less than Array length are visited.
4285 *
4286 * If a ArrayConcatVisitor object is given, the visitor is called with
4287 * parameters, element's index + visitor_index_offset and the element.
4288 */
4289static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
4290 ArrayConcatVisitor* visitor) {
4291 uint32_t range = static_cast<uint32_t>(array->length()->Number());
4292 Handle<Object> obj = array;
4293
4294 static const int kEstimatedPrototypes = 3;
4295 List< Handle<JSObject> > objects(kEstimatedPrototypes);
4296
4297 // Visit prototype first. If an element on the prototype is shadowed by
4298 // the inheritor using the same index, the ArrayConcatVisitor visits
4299 // the prototype element before the shadowing element.
4300 // The visitor can simply overwrite the old value by new value using
4301 // the same index. This follows Array::concat semantics.
4302 while (!obj->IsNull()) {
4303 objects.Add(Handle<JSObject>::cast(obj));
4304 obj = Handle<Object>(obj->GetPrototype());
4305 }
4306
4307 uint32_t nof_elements = 0;
4308 for (int i = objects.length() - 1; i >= 0; i--) {
4309 Handle<JSObject> obj = objects[i];
4310 nof_elements +=
4311 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
4312 }
4313
4314 return nof_elements;
4315}
4316
4317
4318/**
4319 * A helper function of Runtime_ArrayConcat.
4320 *
4321 * The first argument is an Array of arrays and objects. It is the
4322 * same as the arguments array of Array::concat JS function.
4323 *
4324 * If an argument is an Array object, the function visits array
4325 * elements. If an argument is not an Array object, the function
4326 * visits the object as if it is an one-element array.
4327 *
4328 * If the result array index overflows 32-bit integer, the rounded
4329 * non-negative number is used as new length. For example, if one
4330 * array length is 2^32 - 1, second array length is 1, the
4331 * concatenated array length is 0.
4332 */
4333static uint32_t IterateArguments(Handle<JSArray> arguments,
4334 ArrayConcatVisitor* visitor) {
4335 uint32_t visited_elements = 0;
4336 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
4337
4338 for (uint32_t i = 0; i < num_of_args; i++) {
4339 Handle<Object> obj(arguments->GetElement(i));
4340 if (obj->IsJSArray()) {
4341 Handle<JSArray> array = Handle<JSArray>::cast(obj);
4342 uint32_t len = static_cast<uint32_t>(array->length()->Number());
4343 uint32_t nof_elements =
4344 IterateArrayAndPrototypeElements(array, visitor);
4345 // Total elements of array and its prototype chain can be more than
4346 // the array length, but ArrayConcat can only concatenate at most
4347 // the array length number of elements.
4348 visited_elements += (nof_elements > len) ? len : nof_elements;
4349 if (visitor) visitor->increase_index_offset(len);
4350
4351 } else {
4352 if (visitor) {
4353 visitor->visit(0, obj);
4354 visitor->increase_index_offset(1);
4355 }
4356 visited_elements++;
4357 }
4358 }
4359 return visited_elements;
4360}
4361
4362
4363/**
4364 * Array::concat implementation.
4365 * See ECMAScript 262, 15.4.4.4.
4366 */
4367static Object* Runtime_ArrayConcat(Arguments args) {
4368 ASSERT(args.length() == 1);
4369 HandleScope handle_scope;
4370
4371 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
4372 Handle<JSArray> arguments(arg_arrays);
4373
4374 // Pass 1: estimate the number of elements of the result
4375 // (it could be more than real numbers if prototype has elements).
4376 uint32_t result_length = 0;
4377 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
4378
4379 { AssertNoAllocation nogc;
4380 for (uint32_t i = 0; i < num_of_args; i++) {
4381 Object* obj = arguments->GetElement(i);
4382 if (obj->IsJSArray()) {
4383 result_length +=
4384 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
4385 } else {
4386 result_length++;
4387 }
4388 }
4389 }
4390
4391 // Allocate an empty array, will set length and content later.
4392 Handle<JSArray> result = Factory::NewJSArray(0);
4393
4394 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
4395 // If estimated number of elements is more than half of length, a
4396 // fixed array (fast case) is more time and space-efficient than a
4397 // dictionary.
4398 bool fast_case = (estimate_nof_elements * 2) >= result_length;
4399
4400 Handle<FixedArray> storage;
4401 if (fast_case) {
4402 // The backing storage array must have non-existing elements to
4403 // preserve holes across concat operations.
4404 storage = Factory::NewFixedArrayWithHoles(result_length);
4405
4406 } else {
4407 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
4408 uint32_t at_least_space_for = estimate_nof_elements +
4409 (estimate_nof_elements >> 2);
4410 storage = Handle<FixedArray>::cast(
4411 Factory::NewDictionary(at_least_space_for));
4412 }
4413
4414 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
4415
4416 ArrayConcatVisitor visitor(storage, result_length, fast_case);
4417
4418 IterateArguments(arguments, &visitor);
4419
4420 result->set_length(*len);
4421 result->set_elements(*storage);
4422
4423 return *result;
4424}
4425
4426
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004427// This will not allocate (flatten the string), but it may run
4428// very slowly for very deeply nested ConsStrings. For debugging use only.
4429static Object* Runtime_GlobalPrint(Arguments args) {
4430 NoHandleAllocation ha;
4431 ASSERT(args.length() == 1);
4432
4433 CONVERT_CHECKED(String, string, args[0]);
4434 StringInputBuffer buffer(string);
4435 while (buffer.has_more()) {
4436 uint16_t character = buffer.GetNext();
4437 PrintF("%c", character);
4438 }
4439 return string;
4440}
4441
4442
4443static Object* Runtime_RemoveArrayHoles(Arguments args) {
4444 ASSERT(args.length() == 1);
4445 // Ignore the case if this is not a JSArray.
4446 if (!args[0]->IsJSArray()) return args[0];
4447 return JSArray::cast(args[0])->RemoveHoles();
4448}
4449
4450
4451// Move contents of argument 0 (an array) to argument 1 (an array)
4452static Object* Runtime_MoveArrayContents(Arguments args) {
4453 ASSERT(args.length() == 2);
4454 CONVERT_CHECKED(JSArray, from, args[0]);
4455 CONVERT_CHECKED(JSArray, to, args[1]);
4456 to->SetContent(FixedArray::cast(from->elements()));
4457 to->set_length(from->length());
4458 from->SetContent(Heap::empty_fixed_array());
4459 from->set_length(0);
4460 return to;
4461}
4462
4463
4464// How many elements does this array have?
4465static Object* Runtime_EstimateNumberOfElements(Arguments args) {
4466 ASSERT(args.length() == 1);
4467 CONVERT_CHECKED(JSArray, array, args[0]);
4468 HeapObject* elements = array->elements();
4469 if (elements->IsDictionary()) {
4470 return Smi::FromInt(Dictionary::cast(elements)->NumberOfElements());
4471 } else {
4472 return array->length();
4473 }
4474}
4475
4476
4477// Returns an array that tells you where in the [0, length) interval an array
4478// might have elements. Can either return keys or intervals. Keys can have
4479// gaps in (undefined). Intervals can also span over some undefined keys.
4480static Object* Runtime_GetArrayKeys(Arguments args) {
4481 ASSERT(args.length() == 2);
4482 HandleScope scope;
4483 CONVERT_CHECKED(JSArray, raw_array, args[0]);
4484 Handle<JSArray> array(raw_array);
4485 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004486 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004487 // Create an array and get all the keys into it, then remove all the
4488 // keys that are not integers in the range 0 to length-1.
4489 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array);
4490 int keys_length = keys->length();
4491 for (int i = 0; i < keys_length; i++) {
4492 Object* key = keys->get(i);
4493 uint32_t index;
4494 if (!Array::IndexFromObject(key, &index) || index >= length) {
4495 // Zap invalid keys.
4496 keys->set_undefined(i);
4497 }
4498 }
4499 return *Factory::NewJSArrayWithElements(keys);
4500 } else {
4501 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
4502 // -1 means start of array.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004503 single_interval->set(0,
4504 Smi::FromInt(-1),
4505 SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004506 Handle<Object> length_object =
4507 Factory::NewNumber(static_cast<double>(length));
4508 single_interval->set(1, *length_object);
4509 return *Factory::NewJSArrayWithElements(single_interval);
4510 }
4511}
4512
4513
4514// DefineAccessor takes an optional final argument which is the
4515// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
4516// to the way accessors are implemented, it is set for both the getter
4517// and setter on the first call to DefineAccessor and ignored on
4518// subsequent calls.
4519static Object* Runtime_DefineAccessor(Arguments args) {
4520 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
4521 // Compute attributes.
4522 PropertyAttributes attributes = NONE;
4523 if (args.length() == 5) {
4524 CONVERT_CHECKED(Smi, attrs, args[4]);
4525 int value = attrs->value();
4526 // Only attribute bits should be set.
4527 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4528 attributes = static_cast<PropertyAttributes>(value);
4529 }
4530
4531 CONVERT_CHECKED(JSObject, obj, args[0]);
4532 CONVERT_CHECKED(String, name, args[1]);
4533 CONVERT_CHECKED(Smi, flag, args[2]);
4534 CONVERT_CHECKED(JSFunction, fun, args[3]);
4535 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
4536}
4537
4538
4539static Object* Runtime_LookupAccessor(Arguments args) {
4540 ASSERT(args.length() == 3);
4541 CONVERT_CHECKED(JSObject, obj, args[0]);
4542 CONVERT_CHECKED(String, name, args[1]);
4543 CONVERT_CHECKED(Smi, flag, args[2]);
4544 return obj->LookupAccessor(name, flag->value() == 0);
4545}
4546
4547
4548// Helper functions for wrapping and unwrapping stack frame ids.
4549static Smi* WrapFrameId(StackFrame::Id id) {
4550 ASSERT(IsAligned(OffsetFrom(id), 4));
4551 return Smi::FromInt(id >> 2);
4552}
4553
4554
4555static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
4556 return static_cast<StackFrame::Id>(wrapped->value() << 2);
4557}
4558
4559
4560// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00004561// args[0]: debug event listener function to set or null or undefined for
4562// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004563// args[1]: object supplied during callback
iposva@chromium.org245aa852009-02-10 00:49:54 +00004564static Object* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004565 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00004566 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
4567 args[0]->IsUndefined() ||
4568 args[0]->IsNull());
4569 Handle<Object> callback = args.at<Object>(0);
4570 Handle<Object> data = args.at<Object>(1);
4571 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004572
4573 return Heap::undefined_value();
4574}
4575
4576
4577static Object* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00004578 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004579 StackGuard::DebugBreak();
4580 return Heap::undefined_value();
4581}
4582
4583
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004584// Find the length of the prototype chain that is to to handled as one. If a
4585// prototype object is hidden it is to be viewed as part of the the object it
4586// is prototype for.
4587static int LocalPrototypeChainLength(JSObject* obj) {
4588 int count = 1;
4589 Object* proto = obj->GetPrototype();
4590 while (proto->IsJSObject() &&
4591 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4592 count++;
4593 proto = JSObject::cast(proto)->GetPrototype();
4594 }
4595 return count;
4596}
4597
4598
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004599static Object* DebugLookupResultValue(Object* receiver, LookupResult* result,
ager@chromium.org32912102009-01-16 10:38:43 +00004600 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004601 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004602 switch (result->type()) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004603 case NORMAL: {
4604 Dictionary* dict =
4605 JSObject::cast(result->holder())->property_dictionary();
4606 value = dict->ValueAt(result->GetDictionaryEntry());
4607 if (value->IsTheHole()) {
4608 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004609 }
4610 return value;
4611 }
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004612 case FIELD:
4613 value =
4614 JSObject::cast(
4615 result->holder())->FastPropertyAt(result->GetFieldIndex());
4616 if (value->IsTheHole()) {
4617 return Heap::undefined_value();
4618 }
4619 return value;
4620 case CONSTANT_FUNCTION:
4621 return result->GetConstantFunction();
4622 case CALLBACKS: {
4623 Object* structure = result->GetCallbackObject();
4624 if (structure->IsProxy()) {
4625 AccessorDescriptor* callback =
4626 reinterpret_cast<AccessorDescriptor*>(
4627 Proxy::cast(structure)->proxy());
4628 value = (callback->getter)(receiver, callback->data);
ager@chromium.org381abbb2009-02-25 13:23:22 +00004629 if (value->IsException()) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004630 value = Top::pending_exception();
4631 Top::clear_pending_exception();
4632 if (caught_exception != NULL) {
4633 *caught_exception = true;
4634 }
4635 }
4636 return value;
4637 } else {
4638 return Heap::undefined_value();
4639 }
4640 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004641 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004642 case MAP_TRANSITION:
4643 case CONSTANT_TRANSITION:
4644 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004645 return Heap::undefined_value();
4646 default:
4647 UNREACHABLE();
4648 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004649 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004650 return Heap::undefined_value();
4651}
4652
4653
ager@chromium.org32912102009-01-16 10:38:43 +00004654// Get debugger related details for an object property.
4655// args[0]: object holding property
4656// args[1]: name of the property
4657//
4658// The array returned contains the following information:
4659// 0: Property value
4660// 1: Property details
4661// 2: Property value is exception
4662// 3: Getter function if defined
4663// 4: Setter function if defined
4664// Items 2-4 are only filled if the property has either a getter or a setter
4665// defined through __defineGetter__ and/or __defineSetter__.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004666static Object* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004667 HandleScope scope;
4668
4669 ASSERT(args.length() == 2);
4670
4671 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4672 CONVERT_ARG_CHECKED(String, name, 1);
4673
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004674 // Skip the global proxy as it has no properties and always delegates to the
4675 // real global object.
4676 if (obj->IsJSGlobalProxy()) {
4677 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4678 }
4679
4680
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004681 // Check if the name is trivially convertible to an index and get the element
4682 // if so.
4683 uint32_t index;
4684 if (name->AsArrayIndex(&index)) {
4685 Handle<FixedArray> details = Factory::NewFixedArray(2);
4686 details->set(0, Runtime::GetElementOrCharAt(obj, index));
4687 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
4688 return *Factory::NewJSArrayWithElements(details);
4689 }
4690
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004691 // Find the number of objects making up this.
4692 int length = LocalPrototypeChainLength(*obj);
4693
4694 // Try local lookup on each of the objects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004695 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004696 Handle<JSObject> jsproto = obj;
4697 for (int i = 0; i < length; i++) {
4698 jsproto->LocalLookup(*name, &result);
4699 if (result.IsProperty()) {
4700 break;
4701 }
4702 if (i < length - 1) {
4703 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4704 }
4705 }
4706
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004707 if (result.IsProperty()) {
ager@chromium.org32912102009-01-16 10:38:43 +00004708 bool caught_exception = false;
ager@chromium.org381abbb2009-02-25 13:23:22 +00004709 Object* value = DebugLookupResultValue(*obj, &result,
4710 &caught_exception);
4711 if (value->IsFailure()) return value;
4712 Handle<Object> value_handle(value);
ager@chromium.org32912102009-01-16 10:38:43 +00004713 // If the callback object is a fixed array then it contains JavaScript
4714 // getter and/or setter.
4715 bool hasJavaScriptAccessors = result.type() == CALLBACKS &&
4716 result.GetCallbackObject()->IsFixedArray();
4717 Handle<FixedArray> details =
4718 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +00004719 details->set(0, *value_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004720 details->set(1, result.GetPropertyDetails().AsSmi());
ager@chromium.org32912102009-01-16 10:38:43 +00004721 if (hasJavaScriptAccessors) {
4722 details->set(2,
4723 caught_exception ? Heap::true_value() : Heap::false_value());
4724 details->set(3, FixedArray::cast(result.GetCallbackObject())->get(0));
4725 details->set(4, FixedArray::cast(result.GetCallbackObject())->get(1));
4726 }
4727
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004728 return *Factory::NewJSArrayWithElements(details);
4729 }
4730 return Heap::undefined_value();
4731}
4732
4733
4734static Object* Runtime_DebugGetProperty(Arguments args) {
4735 HandleScope scope;
4736
4737 ASSERT(args.length() == 2);
4738
4739 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4740 CONVERT_ARG_CHECKED(String, name, 1);
4741
4742 LookupResult result;
4743 obj->Lookup(*name, &result);
4744 if (result.IsProperty()) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004745 return DebugLookupResultValue(*obj, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004746 }
4747 return Heap::undefined_value();
4748}
4749
4750
4751// Return the names of the local named properties.
4752// args[0]: object
4753static Object* Runtime_DebugLocalPropertyNames(Arguments args) {
4754 HandleScope scope;
4755 ASSERT(args.length() == 1);
4756 if (!args[0]->IsJSObject()) {
4757 return Heap::undefined_value();
4758 }
4759 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4760
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004761 // Skip the global proxy as it has no properties and always delegates to the
4762 // real global object.
4763 if (obj->IsJSGlobalProxy()) {
4764 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4765 }
4766
4767 // Find the number of objects making up this.
4768 int length = LocalPrototypeChainLength(*obj);
4769
4770 // Find the number of local properties for each of the objects.
4771 int* local_property_count = NewArray<int>(length);
4772 int total_property_count = 0;
4773 Handle<JSObject> jsproto = obj;
4774 for (int i = 0; i < length; i++) {
4775 int n;
4776 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4777 local_property_count[i] = n;
4778 total_property_count += n;
4779 if (i < length - 1) {
4780 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4781 }
4782 }
4783
4784 // Allocate an array with storage for all the property names.
4785 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
4786
4787 // Get the property names.
4788 jsproto = obj;
4789 for (int i = 0; i < length; i++) {
4790 jsproto->GetLocalPropertyNames(*names,
4791 i == 0 ? 0 : local_property_count[i - 1]);
4792 if (i < length - 1) {
4793 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4794 }
4795 }
4796
4797 DeleteArray(local_property_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004798 return *Factory::NewJSArrayWithElements(names);
4799}
4800
4801
4802// Return the names of the local indexed properties.
4803// args[0]: object
4804static Object* Runtime_DebugLocalElementNames(Arguments args) {
4805 HandleScope scope;
4806 ASSERT(args.length() == 1);
4807 if (!args[0]->IsJSObject()) {
4808 return Heap::undefined_value();
4809 }
4810 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4811
4812 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4813 Handle<FixedArray> names = Factory::NewFixedArray(n);
4814 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4815 return *Factory::NewJSArrayWithElements(names);
4816}
4817
4818
4819// Return the property type calculated from the property details.
4820// args[0]: smi with property details.
4821static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
4822 ASSERT(args.length() == 1);
4823 CONVERT_CHECKED(Smi, details, args[0]);
4824 PropertyType type = PropertyDetails(details).type();
4825 return Smi::FromInt(static_cast<int>(type));
4826}
4827
4828
4829// Return the property attribute calculated from the property details.
4830// args[0]: smi with property details.
4831static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
4832 ASSERT(args.length() == 1);
4833 CONVERT_CHECKED(Smi, details, args[0]);
4834 PropertyAttributes attributes = PropertyDetails(details).attributes();
4835 return Smi::FromInt(static_cast<int>(attributes));
4836}
4837
4838
4839// Return the property insertion index calculated from the property details.
4840// args[0]: smi with property details.
4841static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
4842 ASSERT(args.length() == 1);
4843 CONVERT_CHECKED(Smi, details, args[0]);
4844 int index = PropertyDetails(details).index();
4845 return Smi::FromInt(index);
4846}
4847
4848
4849// Return information on whether an object has a named or indexed interceptor.
4850// args[0]: object
4851static Object* Runtime_DebugInterceptorInfo(Arguments args) {
4852 HandleScope scope;
4853 ASSERT(args.length() == 1);
4854 if (!args[0]->IsJSObject()) {
4855 return Smi::FromInt(0);
4856 }
4857 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4858
4859 int result = 0;
4860 if (obj->HasNamedInterceptor()) result |= 2;
4861 if (obj->HasIndexedInterceptor()) result |= 1;
4862
4863 return Smi::FromInt(result);
4864}
4865
4866
4867// Return property names from named interceptor.
4868// args[0]: object
4869static Object* Runtime_DebugNamedInterceptorPropertyNames(Arguments args) {
4870 HandleScope scope;
4871 ASSERT(args.length() == 1);
4872 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004873
ager@chromium.org32912102009-01-16 10:38:43 +00004874 if (obj->HasNamedInterceptor()) {
4875 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4876 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4877 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004878 return Heap::undefined_value();
4879}
4880
4881
4882// Return element names from indexed interceptor.
4883// args[0]: object
4884static Object* Runtime_DebugIndexedInterceptorElementNames(Arguments args) {
4885 HandleScope scope;
4886 ASSERT(args.length() == 1);
4887 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004888
ager@chromium.org32912102009-01-16 10:38:43 +00004889 if (obj->HasIndexedInterceptor()) {
4890 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4891 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4892 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893 return Heap::undefined_value();
4894}
4895
4896
4897// Return property value from named interceptor.
4898// args[0]: object
4899// args[1]: property name
4900static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
4901 HandleScope scope;
4902 ASSERT(args.length() == 2);
4903 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4904 RUNTIME_ASSERT(obj->HasNamedInterceptor());
4905 CONVERT_ARG_CHECKED(String, name, 1);
4906
4907 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004908 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004909}
4910
4911
4912// Return element value from indexed interceptor.
4913// args[0]: object
4914// args[1]: index
4915static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) {
4916 HandleScope scope;
4917 ASSERT(args.length() == 2);
4918 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4919 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
4920 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
4921
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004922 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004923}
4924
4925
4926static Object* Runtime_CheckExecutionState(Arguments args) {
4927 ASSERT(args.length() >= 1);
4928 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00004929 // Check that the break id is valid.
4930 if (Top::break_id() == 0 || break_id != Top::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004931 return Top::Throw(Heap::illegal_execution_state_symbol());
4932 }
4933
4934 return Heap::true_value();
4935}
4936
4937
4938static Object* Runtime_GetFrameCount(Arguments args) {
4939 HandleScope scope;
4940 ASSERT(args.length() == 1);
4941
4942 // Check arguments.
4943 Object* result = Runtime_CheckExecutionState(args);
4944 if (result->IsFailure()) return result;
4945
4946 // Count all frames which are relevant to debugging stack trace.
4947 int n = 0;
4948 StackFrame::Id id = Top::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00004949 if (id == StackFrame::NO_ID) {
4950 // If there is no JavaScript stack frame count is 0.
4951 return Smi::FromInt(0);
4952 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004953 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
4954 return Smi::FromInt(n);
4955}
4956
4957
4958static const int kFrameDetailsFrameIdIndex = 0;
4959static const int kFrameDetailsReceiverIndex = 1;
4960static const int kFrameDetailsFunctionIndex = 2;
4961static const int kFrameDetailsArgumentCountIndex = 3;
4962static const int kFrameDetailsLocalCountIndex = 4;
4963static const int kFrameDetailsSourcePositionIndex = 5;
4964static const int kFrameDetailsConstructCallIndex = 6;
4965static const int kFrameDetailsDebuggerFrameIndex = 7;
4966static const int kFrameDetailsFirstDynamicIndex = 8;
4967
4968// Return an array with frame details
4969// args[0]: number: break id
4970// args[1]: number: frame index
4971//
4972// The array returned contains the following information:
4973// 0: Frame id
4974// 1: Receiver
4975// 2: Function
4976// 3: Argument count
4977// 4: Local count
4978// 5: Source position
4979// 6: Constructor call
4980// 7: Debugger frame
4981// Arguments name, value
4982// Locals name, value
4983static Object* Runtime_GetFrameDetails(Arguments args) {
4984 HandleScope scope;
4985 ASSERT(args.length() == 2);
4986
4987 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004988 Object* check = Runtime_CheckExecutionState(args);
4989 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004990 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
4991
4992 // Find the relevant frame with the requested index.
4993 StackFrame::Id id = Top::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00004994 if (id == StackFrame::NO_ID) {
4995 // If there are no JavaScript stack frames return undefined.
4996 return Heap::undefined_value();
4997 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004998 int count = 0;
4999 JavaScriptFrameIterator it(id);
5000 for (; !it.done(); it.Advance()) {
5001 if (count == index) break;
5002 count++;
5003 }
5004 if (it.done()) return Heap::undefined_value();
5005
5006 // Traverse the saved contexts chain to find the active context for the
5007 // selected frame.
5008 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005009 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005010 save = save->prev();
5011 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005012 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005013
5014 // Get the frame id.
5015 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
5016
5017 // Find source position.
5018 int position = it.frame()->FindCode()->SourcePosition(it.frame()->pc());
5019
5020 // Check for constructor frame.
5021 bool constructor = it.frame()->IsConstructor();
5022
5023 // Get code and read scope info from it for local variable information.
5024 Handle<Code> code(it.frame()->FindCode());
5025 ScopeInfo<> info(*code);
5026
5027 // Get the context.
5028 Handle<Context> context(Context::cast(it.frame()->context()));
5029
5030 // Get the locals names and values into a temporary array.
5031 //
5032 // TODO(1240907): Hide compiler-introduced stack variables
5033 // (e.g. .result)? For users of the debugger, they will probably be
5034 // confusing.
5035 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
5036 for (int i = 0; i < info.NumberOfLocals(); i++) {
5037 // Name of the local.
5038 locals->set(i * 2, *info.LocalName(i));
5039
5040 // Fetch the value of the local - either from the stack or from a
5041 // heap-allocated context.
5042 if (i < info.number_of_stack_slots()) {
5043 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
5044 } else {
5045 Handle<String> name = info.LocalName(i);
5046 // Traverse the context chain to the function context as all local
5047 // variables stored in the context will be on the function context.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005048 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005049 context = Handle<Context>(context->previous());
5050 }
5051 ASSERT(context->is_function_context());
5052 locals->set(i * 2 + 1,
5053 context->get(ScopeInfo<>::ContextSlotIndex(*code, *name,
5054 NULL)));
5055 }
5056 }
5057
5058 // Now advance to the arguments adapter frame (if any). If contains all
5059 // the provided parameters and
5060
5061 // Now advance to the arguments adapter frame (if any). It contains all
5062 // the provided parameters whereas the function frame always have the number
5063 // of arguments matching the functions parameters. The rest of the
5064 // information (except for what is collected above) is the same.
5065 it.AdvanceToArgumentsFrame();
5066
5067 // Find the number of arguments to fill. At least fill the number of
5068 // parameters for the function and fill more if more parameters are provided.
5069 int argument_count = info.number_of_parameters();
5070 if (argument_count < it.frame()->GetProvidedParametersCount()) {
5071 argument_count = it.frame()->GetProvidedParametersCount();
5072 }
5073
5074 // Calculate the size of the result.
5075 int details_size = kFrameDetailsFirstDynamicIndex +
5076 2 * (argument_count + info.NumberOfLocals());
5077 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
5078
5079 // Add the frame id.
5080 details->set(kFrameDetailsFrameIdIndex, *frame_id);
5081
5082 // Add the function (same as in function frame).
5083 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
5084
5085 // Add the arguments count.
5086 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
5087
5088 // Add the locals count
5089 details->set(kFrameDetailsLocalCountIndex,
5090 Smi::FromInt(info.NumberOfLocals()));
5091
5092 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00005093 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005094 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
5095 } else {
5096 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
5097 }
5098
5099 // Add the constructor information.
5100 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
5101
5102 // Add information on whether this frame is invoked in the debugger context.
5103 details->set(kFrameDetailsDebuggerFrameIndex,
5104 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
5105
5106 // Fill the dynamic part.
5107 int details_index = kFrameDetailsFirstDynamicIndex;
5108
5109 // Add arguments name and value.
5110 for (int i = 0; i < argument_count; i++) {
5111 // Name of the argument.
5112 if (i < info.number_of_parameters()) {
5113 details->set(details_index++, *info.parameter_name(i));
5114 } else {
5115 details->set(details_index++, Heap::undefined_value());
5116 }
5117
5118 // Parameter value.
5119 if (i < it.frame()->GetProvidedParametersCount()) {
5120 details->set(details_index++, it.frame()->GetParameter(i));
5121 } else {
5122 details->set(details_index++, Heap::undefined_value());
5123 }
5124 }
5125
5126 // Add locals name and value from the temporary copy from the function frame.
5127 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
5128 details->set(details_index++, locals->get(i));
5129 }
5130
5131 // Add the receiver (same as in function frame).
5132 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
5133 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
5134 Handle<Object> receiver(it.frame()->receiver());
5135 if (!receiver->IsJSObject()) {
5136 // If the receiver is NOT a JSObject we have hit an optimization
5137 // where a value object is not converted into a wrapped JS objects.
5138 // To hide this optimization from the debugger, we wrap the receiver
5139 // by creating correct wrapper object based on the calling frame's
5140 // global context.
5141 it.Advance();
5142 Handle<Context> calling_frames_global_context(
5143 Context::cast(Context::cast(it.frame()->context())->global_context()));
5144 receiver = Factory::ToObject(receiver, calling_frames_global_context);
5145 }
5146 details->set(kFrameDetailsReceiverIndex, *receiver);
5147
5148 ASSERT_EQ(details_size, details_index);
5149 return *Factory::NewJSArrayWithElements(details);
5150}
5151
5152
5153static Object* Runtime_GetCFrames(Arguments args) {
5154 HandleScope scope;
5155 ASSERT(args.length() == 1);
5156 Object* result = Runtime_CheckExecutionState(args);
5157 if (result->IsFailure()) return result;
5158
5159 static const int kMaxCFramesSize = 200;
5160 OS::StackFrame frames[kMaxCFramesSize];
5161 int frames_count = OS::StackWalk(frames, kMaxCFramesSize);
5162 if (frames_count == OS::kStackWalkError) {
5163 return Heap::undefined_value();
5164 }
5165
5166 Handle<String> address_str = Factory::LookupAsciiSymbol("address");
5167 Handle<String> text_str = Factory::LookupAsciiSymbol("text");
5168 Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count);
5169 for (int i = 0; i < frames_count; i++) {
5170 Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function());
5171 frame_value->SetProperty(
5172 *address_str,
5173 *Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address)),
5174 NONE);
5175
5176 // Get the stack walk text for this frame.
5177 Handle<String> frame_text;
5178 if (strlen(frames[i].text) > 0) {
5179 Vector<const char> str(frames[i].text, strlen(frames[i].text));
5180 frame_text = Factory::NewStringFromAscii(str);
5181 }
5182
5183 if (!frame_text.is_null()) {
5184 frame_value->SetProperty(*text_str, *frame_text, NONE);
5185 }
5186
5187 frames_array->set(i, *frame_value);
5188 }
5189 return *Factory::NewJSArrayWithElements(frames_array);
5190}
5191
5192
5193static Object* Runtime_GetBreakLocations(Arguments args) {
5194 HandleScope scope;
5195 ASSERT(args.length() == 1);
5196
5197 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
5198 Handle<SharedFunctionInfo> shared(raw_fun->shared());
5199 // Find the number of break points
5200 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
5201 if (break_locations->IsUndefined()) return Heap::undefined_value();
5202 // Return array as JS array
5203 return *Factory::NewJSArrayWithElements(
5204 Handle<FixedArray>::cast(break_locations));
5205}
5206
5207
5208// Set a break point in a function
5209// args[0]: function
5210// args[1]: number: break source position (within the function source)
5211// args[2]: number: break point object
5212static Object* Runtime_SetFunctionBreakPoint(Arguments args) {
5213 HandleScope scope;
5214 ASSERT(args.length() == 3);
5215 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
5216 Handle<SharedFunctionInfo> shared(raw_fun->shared());
5217 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
5218 RUNTIME_ASSERT(source_position >= 0);
5219 Handle<Object> break_point_object_arg = args.at<Object>(2);
5220
5221 // Set break point.
5222 Debug::SetBreakPoint(shared, source_position, break_point_object_arg);
5223
5224 return Heap::undefined_value();
5225}
5226
5227
5228static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
5229 int position) {
5230 // Iterate the heap looking for SharedFunctionInfo generated from the
5231 // script. The inner most SharedFunctionInfo containing the source position
5232 // for the requested break point is found.
5233 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
5234 // which is found is not compiled it is compiled and the heap is iterated
5235 // again as the compilation might create inner functions from the newly
5236 // compiled function and the actual requested break point might be in one of
5237 // these functions.
5238 bool done = false;
5239 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00005240 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005241 Handle<SharedFunctionInfo> target;
5242 // The current candidate for the last function in script:
5243 Handle<SharedFunctionInfo> last;
5244 while (!done) {
5245 HeapIterator iterator;
5246 while (iterator.has_next()) {
5247 HeapObject* obj = iterator.next();
5248 ASSERT(obj != NULL);
5249 if (obj->IsSharedFunctionInfo()) {
5250 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
5251 if (shared->script() == *script) {
5252 // If the SharedFunctionInfo found has the requested script data and
5253 // contains the source position it is a candidate.
5254 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00005255 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005256 start_position = shared->start_position();
5257 }
5258 if (start_position <= position &&
5259 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00005260 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005261 // candidate this is the new candidate.
5262 if (target.is_null()) {
5263 target_start_position = start_position;
5264 target = shared;
5265 } else {
5266 if (target_start_position < start_position &&
5267 shared->end_position() < target->end_position()) {
5268 target_start_position = start_position;
5269 target = shared;
5270 }
5271 }
5272 }
5273
5274 // Keep track of the last function in the script.
5275 if (last.is_null() ||
5276 shared->end_position() > last->start_position()) {
5277 last = shared;
5278 }
5279 }
5280 }
5281 }
5282
5283 // Make sure some candidate is selected.
5284 if (target.is_null()) {
5285 if (!last.is_null()) {
5286 // Position after the last function - use last.
5287 target = last;
5288 } else {
5289 // Unable to find function - possibly script without any function.
5290 return Heap::undefined_value();
5291 }
5292 }
5293
5294 // If the candidate found is compiled we are done. NOTE: when lazy
5295 // compilation of inner functions is introduced some additional checking
5296 // needs to be done here to compile inner functions.
5297 done = target->is_compiled();
5298 if (!done) {
5299 // If the candidate is not compiled compile it to reveal any inner
5300 // functions which might contain the requested source position.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005301 CompileLazyShared(target, KEEP_EXCEPTION, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005302 }
5303 }
5304
5305 return *target;
5306}
5307
5308
5309// Change the state of a break point in a script. NOTE: Regarding performance
5310// see the NOTE for GetScriptFromScriptData.
5311// args[0]: script to set break point in
5312// args[1]: number: break source position (within the script source)
5313// args[2]: number: break point object
5314static Object* Runtime_SetScriptBreakPoint(Arguments args) {
5315 HandleScope scope;
5316 ASSERT(args.length() == 3);
5317 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
5318 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
5319 RUNTIME_ASSERT(source_position >= 0);
5320 Handle<Object> break_point_object_arg = args.at<Object>(2);
5321
5322 // Get the script from the script wrapper.
5323 RUNTIME_ASSERT(wrapper->value()->IsScript());
5324 Handle<Script> script(Script::cast(wrapper->value()));
5325
5326 Object* result = FindSharedFunctionInfoInScript(script, source_position);
5327 if (!result->IsUndefined()) {
5328 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
5329 // Find position within function. The script position might be before the
5330 // source position of the first function.
5331 int position;
5332 if (shared->start_position() > source_position) {
5333 position = 0;
5334 } else {
5335 position = source_position - shared->start_position();
5336 }
5337 Debug::SetBreakPoint(shared, position, break_point_object_arg);
5338 }
5339 return Heap::undefined_value();
5340}
5341
5342
5343// Clear a break point
5344// args[0]: number: break point object
5345static Object* Runtime_ClearBreakPoint(Arguments args) {
5346 HandleScope scope;
5347 ASSERT(args.length() == 1);
5348 Handle<Object> break_point_object_arg = args.at<Object>(0);
5349
5350 // Clear break point.
5351 Debug::ClearBreakPoint(break_point_object_arg);
5352
5353 return Heap::undefined_value();
5354}
5355
5356
5357// Change the state of break on exceptions
5358// args[0]: boolean indicating uncaught exceptions
5359// args[1]: boolean indicating on/off
5360static Object* Runtime_ChangeBreakOnException(Arguments args) {
5361 HandleScope scope;
5362 ASSERT(args.length() == 2);
5363 ASSERT(args[0]->IsNumber());
5364 ASSERT(args[1]->IsBoolean());
5365
5366 // Update break point state
5367 ExceptionBreakType type =
5368 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
5369 bool enable = args[1]->ToBoolean()->IsTrue();
5370 Debug::ChangeBreakOnException(type, enable);
5371 return Heap::undefined_value();
5372}
5373
5374
5375// Prepare for stepping
5376// args[0]: break id for checking execution state
5377// args[1]: step action from the enumeration StepAction
5378// args[2]: number of times to perform the step
5379static Object* Runtime_PrepareStep(Arguments args) {
5380 HandleScope scope;
5381 ASSERT(args.length() == 3);
5382 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005383 Object* check = Runtime_CheckExecutionState(args);
5384 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005385 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
5386 return Top::Throw(Heap::illegal_argument_symbol());
5387 }
5388
5389 // Get the step action and check validity.
5390 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
5391 if (step_action != StepIn &&
5392 step_action != StepNext &&
5393 step_action != StepOut &&
5394 step_action != StepInMin &&
5395 step_action != StepMin) {
5396 return Top::Throw(Heap::illegal_argument_symbol());
5397 }
5398
5399 // Get the number of steps.
5400 int step_count = NumberToInt32(args[2]);
5401 if (step_count < 1) {
5402 return Top::Throw(Heap::illegal_argument_symbol());
5403 }
5404
5405 // Prepare step.
5406 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
5407 return Heap::undefined_value();
5408}
5409
5410
5411// Clear all stepping set by PrepareStep.
5412static Object* Runtime_ClearStepping(Arguments args) {
5413 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00005414 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005415 Debug::ClearStepping();
5416 return Heap::undefined_value();
5417}
5418
5419
5420// Creates a copy of the with context chain. The copy of the context chain is
5421// is linked to the function context supplied.
5422static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
5423 Handle<Context> function_context) {
5424 // At the bottom of the chain. Return the function context to link to.
5425 if (context_chain->is_function_context()) {
5426 return function_context;
5427 }
5428
5429 // Recursively copy the with contexts.
5430 Handle<Context> previous(context_chain->previous());
5431 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
5432 return Factory::NewWithContext(
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005433 CopyWithContextChain(function_context, previous),
5434 extension,
5435 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005436}
5437
5438
5439// Helper function to find or create the arguments object for
5440// Runtime_DebugEvaluate.
5441static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
5442 Handle<JSFunction> function,
5443 Handle<Code> code,
5444 const ScopeInfo<>* sinfo,
5445 Handle<Context> function_context) {
5446 // Try to find the value of 'arguments' to pass as parameter. If it is not
5447 // found (that is the debugged function does not reference 'arguments' and
5448 // does not support eval) then create an 'arguments' object.
5449 int index;
5450 if (sinfo->number_of_stack_slots() > 0) {
5451 index = ScopeInfo<>::StackSlotIndex(*code, Heap::arguments_symbol());
5452 if (index != -1) {
5453 return Handle<Object>(frame->GetExpression(index));
5454 }
5455 }
5456
5457 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
5458 index = ScopeInfo<>::ContextSlotIndex(*code, Heap::arguments_symbol(),
5459 NULL);
5460 if (index != -1) {
5461 return Handle<Object>(function_context->get(index));
5462 }
5463 }
5464
5465 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005466 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
5467 Handle<FixedArray> array = Factory::NewFixedArray(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005468 WriteBarrierMode mode = array->GetWriteBarrierMode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005469 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005470 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005471 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005472 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005473 return arguments;
5474}
5475
5476
5477// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00005478// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479// extension part has all the parameters and locals of the function on the
5480// stack frame. A function which calls eval with the code to evaluate is then
5481// compiled in this context and called in this context. As this context
5482// replaces the context of the function on the stack frame a new (empty)
5483// function is created as well to be used as the closure for the context.
5484// This function and the context acts as replacements for the function on the
5485// stack frame presenting the same view of the values of parameters and
5486// local variables as if the piece of JavaScript was evaluated at the point
5487// where the function on the stack frame is currently stopped.
5488static Object* Runtime_DebugEvaluate(Arguments args) {
5489 HandleScope scope;
5490
5491 // Check the execution state and decode arguments frame and source to be
5492 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005493 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005494 Object* check_result = Runtime_CheckExecutionState(args);
5495 if (check_result->IsFailure()) return check_result;
5496 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
5497 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005498 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
5499
5500 // Handle the processing of break.
5501 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005502
5503 // Get the frame where the debugging is performed.
5504 StackFrame::Id id = UnwrapFrameId(wrapped_id);
5505 JavaScriptFrameIterator it(id);
5506 JavaScriptFrame* frame = it.frame();
5507 Handle<JSFunction> function(JSFunction::cast(frame->function()));
5508 Handle<Code> code(function->code());
5509 ScopeInfo<> sinfo(*code);
5510
5511 // Traverse the saved contexts chain to find the active context for the
5512 // selected frame.
5513 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005514 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005515 save = save->prev();
5516 }
5517 ASSERT(save != NULL);
5518 SaveContext savex;
5519 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005520
5521 // Create the (empty) function replacing the function on the stack frame for
5522 // the purpose of evaluating in the context created below. It is important
5523 // that this function does not describe any parameters and local variables
5524 // in the context. If it does then this will cause problems with the lookup
5525 // in Context::Lookup, where context slots for parameters and local variables
5526 // are looked at before the extension object.
5527 Handle<JSFunction> go_between =
5528 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
5529 go_between->set_context(function->context());
5530#ifdef DEBUG
5531 ScopeInfo<> go_between_sinfo(go_between->shared()->code());
5532 ASSERT(go_between_sinfo.number_of_parameters() == 0);
5533 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
5534#endif
5535
5536 // Allocate and initialize a context extension object with all the
5537 // arguments, stack locals heap locals and extension properties of the
5538 // debugged function.
5539 Handle<JSObject> context_ext = Factory::NewJSObject(Top::object_function());
5540 // First fill all parameters to the context extension.
5541 for (int i = 0; i < sinfo.number_of_parameters(); ++i) {
5542 SetProperty(context_ext,
5543 sinfo.parameter_name(i),
5544 Handle<Object>(frame->GetParameter(i)), NONE);
5545 }
5546 // Second fill all stack locals to the context extension.
5547 for (int i = 0; i < sinfo.number_of_stack_slots(); i++) {
5548 SetProperty(context_ext,
5549 sinfo.stack_slot_name(i),
5550 Handle<Object>(frame->GetExpression(i)), NONE);
5551 }
5552 // Third fill all context locals to the context extension.
5553 Handle<Context> frame_context(Context::cast(frame->context()));
5554 Handle<Context> function_context(frame_context->fcontext());
5555 for (int i = Context::MIN_CONTEXT_SLOTS;
5556 i < sinfo.number_of_context_slots();
5557 ++i) {
5558 int context_index =
5559 ScopeInfo<>::ContextSlotIndex(*code, *sinfo.context_slot_name(i), NULL);
5560 SetProperty(context_ext,
5561 sinfo.context_slot_name(i),
5562 Handle<Object>(function_context->get(context_index)), NONE);
5563 }
5564 // Finally copy any properties from the function context extension. This will
5565 // be variables introduced by eval.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005566 if (function_context->has_extension() &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005567 !function_context->IsGlobalContext()) {
5568 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
5569 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext);
5570 for (int i = 0; i < keys->length(); i++) {
5571 // Names of variables introduced by eval are strings.
5572 ASSERT(keys->get(i)->IsString());
5573 Handle<String> key(String::cast(keys->get(i)));
5574 SetProperty(context_ext, key, GetProperty(ext, key), NONE);
5575 }
5576 }
5577
5578 // Allocate a new context for the debug evaluation and set the extension
5579 // object build.
5580 Handle<Context> context =
5581 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
5582 context->set_extension(*context_ext);
5583 // Copy any with contexts present and chain them in front of this context.
5584 context = CopyWithContextChain(frame_context, context);
5585
5586 // Wrap the evaluation statement in a new function compiled in the newly
5587 // created context. The function has one parameter which has to be called
5588 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00005589 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005590 // function(arguments,__source__) {return eval(__source__);}
5591 static const char* source_str =
5592 "function(arguments,__source__){return eval(__source__);}";
5593 static const int source_str_length = strlen(source_str);
5594 Handle<String> function_source =
5595 Factory::NewStringFromAscii(Vector<const char>(source_str,
5596 source_str_length));
5597 Handle<JSFunction> boilerplate =
ager@chromium.org381abbb2009-02-25 13:23:22 +00005598 Compiler::CompileEval(function_source,
5599 context,
5600 0,
5601 context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005602 if (boilerplate.is_null()) return Failure::Exception();
5603 Handle<JSFunction> compiled_function =
5604 Factory::NewFunctionFromBoilerplate(boilerplate, context);
5605
5606 // Invoke the result of the compilation to get the evaluation function.
5607 bool has_pending_exception;
5608 Handle<Object> receiver(frame->receiver());
5609 Handle<Object> evaluation_function =
5610 Execution::Call(compiled_function, receiver, 0, NULL,
5611 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005612 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005613
5614 Handle<Object> arguments = GetArgumentsObject(frame, function, code, &sinfo,
5615 function_context);
5616
5617 // Invoke the evaluation function and return the result.
5618 const int argc = 2;
5619 Object** argv[argc] = { arguments.location(),
5620 Handle<Object>::cast(source).location() };
5621 Handle<Object> result =
5622 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
5623 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005624 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005625 return *result;
5626}
5627
5628
5629static Object* Runtime_DebugEvaluateGlobal(Arguments args) {
5630 HandleScope scope;
5631
5632 // Check the execution state and decode arguments frame and source to be
5633 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005634 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005635 Object* check_result = Runtime_CheckExecutionState(args);
5636 if (check_result->IsFailure()) return check_result;
5637 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005638 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
5639
5640 // Handle the processing of break.
5641 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005642
5643 // Enter the top context from before the debugger was invoked.
5644 SaveContext save;
5645 SaveContext* top = &save;
5646 while (top != NULL && *top->context() == *Debug::debug_context()) {
5647 top = top->prev();
5648 }
5649 if (top != NULL) {
5650 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005651 }
5652
5653 // Get the global context now set to the top context from before the
5654 // debugger was invoked.
5655 Handle<Context> context = Top::global_context();
5656
5657 // Compile the source to be evaluated.
ager@chromium.org381abbb2009-02-25 13:23:22 +00005658 Handle<JSFunction> boilerplate =
5659 Handle<JSFunction>(Compiler::CompileEval(source, context, 0, true));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005660 if (boilerplate.is_null()) return Failure::Exception();
5661 Handle<JSFunction> compiled_function =
5662 Handle<JSFunction>(Factory::NewFunctionFromBoilerplate(boilerplate,
5663 context));
5664
5665 // Invoke the result of the compilation to get the evaluation function.
5666 bool has_pending_exception;
5667 Handle<Object> receiver = Top::global();
5668 Handle<Object> result =
5669 Execution::Call(compiled_function, receiver, 0, NULL,
5670 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005671 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005672 return *result;
5673}
5674
5675
5676// Helper function used by Runtime_DebugGetLoadedScripts below.
5677static int DebugGetLoadedScripts(FixedArray* instances, int instances_size) {
5678 NoHandleAllocation ha;
5679 AssertNoAllocation no_alloc;
5680
5681 // Get hold of the current empty script.
5682 Context* context = Top::context()->global_context();
5683 Script* empty = context->empty_script();
5684
5685 // Scan heap for Script objects.
5686 int count = 0;
5687 HeapIterator iterator;
5688 while (iterator.has_next()) {
5689 HeapObject* obj = iterator.next();
5690 ASSERT(obj != NULL);
5691 if (obj->IsScript() && obj != empty) {
5692 if (instances != NULL && count < instances_size) {
5693 instances->set(count, obj);
5694 }
5695 count++;
5696 }
5697 }
5698
5699 return count;
5700}
5701
5702
5703static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
5704 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00005705 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005706
5707 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
ager@chromium.org32912102009-01-16 10:38:43 +00005708 // rid of all the cached script wrappers and the second gets rid of the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005709 // scripts which is no longer referenced.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005710 Heap::CollectAllGarbage();
5711 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005712
5713 // Get the number of scripts.
5714 int count;
5715 count = DebugGetLoadedScripts(NULL, 0);
5716
5717 // Allocate an array to hold the result.
5718 Handle<FixedArray> instances = Factory::NewFixedArray(count);
5719
5720 // Fill the script objects.
5721 count = DebugGetLoadedScripts(*instances, count);
5722
5723 // Convert the script objects to proper JS objects.
5724 for (int i = 0; i < count; i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005725 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
5726 // Get the script wrapper in a local handle before calling GetScriptWrapper,
5727 // because using
5728 // instances->set(i, *GetScriptWrapper(script))
5729 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
5730 // already have deferenced the instances handle.
5731 Handle<JSValue> wrapper = GetScriptWrapper(script);
5732 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005733 }
5734
5735 // Return result as a JS array.
5736 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
5737 Handle<JSArray>::cast(result)->SetContent(*instances);
5738 return *result;
5739}
5740
5741
5742// Helper function used by Runtime_DebugReferencedBy below.
5743static int DebugReferencedBy(JSObject* target,
5744 Object* instance_filter, int max_references,
5745 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005746 JSFunction* arguments_function) {
5747 NoHandleAllocation ha;
5748 AssertNoAllocation no_alloc;
5749
5750 // Iterate the heap.
5751 int count = 0;
5752 JSObject* last = NULL;
5753 HeapIterator iterator;
5754 while (iterator.has_next() &&
5755 (max_references == 0 || count < max_references)) {
5756 // Only look at all JSObjects.
5757 HeapObject* heap_obj = iterator.next();
5758 if (heap_obj->IsJSObject()) {
5759 // Skip context extension objects and argument arrays as these are
5760 // checked in the context of functions using them.
5761 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +00005762 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005763 obj->map()->constructor() == arguments_function) {
5764 continue;
5765 }
5766
5767 // Check if the JS object has a reference to the object looked for.
5768 if (obj->ReferencesObject(target)) {
5769 // Check instance filter if supplied. This is normally used to avoid
5770 // references from mirror objects (see Runtime_IsInPrototypeChain).
5771 if (!instance_filter->IsUndefined()) {
5772 Object* V = obj;
5773 while (true) {
5774 Object* prototype = V->GetPrototype();
5775 if (prototype->IsNull()) {
5776 break;
5777 }
5778 if (instance_filter == prototype) {
5779 obj = NULL; // Don't add this object.
5780 break;
5781 }
5782 V = prototype;
5783 }
5784 }
5785
5786 if (obj != NULL) {
5787 // Valid reference found add to instance array if supplied an update
5788 // count.
5789 if (instances != NULL && count < instances_size) {
5790 instances->set(count, obj);
5791 }
5792 last = obj;
5793 count++;
5794 }
5795 }
5796 }
5797 }
5798
5799 // Check for circular reference only. This can happen when the object is only
5800 // referenced from mirrors and has a circular reference in which case the
5801 // object is not really alive and would have been garbage collected if not
5802 // referenced from the mirror.
5803 if (count == 1 && last == target) {
5804 count = 0;
5805 }
5806
5807 // Return the number of referencing objects found.
5808 return count;
5809}
5810
5811
5812// Scan the heap for objects with direct references to an object
5813// args[0]: the object to find references to
5814// args[1]: constructor function for instances to exclude (Mirror)
5815// args[2]: the the maximum number of objects to return
5816static Object* Runtime_DebugReferencedBy(Arguments args) {
5817 ASSERT(args.length() == 3);
5818
5819 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005820 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005821
5822 // Check parameters.
5823 CONVERT_CHECKED(JSObject, target, args[0]);
5824 Object* instance_filter = args[1];
5825 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
5826 instance_filter->IsJSObject());
5827 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
5828 RUNTIME_ASSERT(max_references >= 0);
5829
5830 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005831 JSObject* arguments_boilerplate =
5832 Top::context()->global_context()->arguments_boilerplate();
5833 JSFunction* arguments_function =
5834 JSFunction::cast(arguments_boilerplate->map()->constructor());
5835
5836 // Get the number of referencing objects.
5837 int count;
5838 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00005839 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005840
5841 // Allocate an array to hold the result.
5842 Object* object = Heap::AllocateFixedArray(count);
5843 if (object->IsFailure()) return object;
5844 FixedArray* instances = FixedArray::cast(object);
5845
5846 // Fill the referencing objects.
5847 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00005848 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005849
5850 // Return result as JS array.
5851 Object* result =
5852 Heap::AllocateJSObject(
5853 Top::context()->global_context()->array_function());
5854 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
5855 return result;
5856}
5857
5858
5859// Helper function used by Runtime_DebugConstructedBy below.
5860static int DebugConstructedBy(JSFunction* constructor, int max_references,
5861 FixedArray* instances, int instances_size) {
5862 AssertNoAllocation no_alloc;
5863
5864 // Iterate the heap.
5865 int count = 0;
5866 HeapIterator iterator;
5867 while (iterator.has_next() &&
5868 (max_references == 0 || count < max_references)) {
5869 // Only look at all JSObjects.
5870 HeapObject* heap_obj = iterator.next();
5871 if (heap_obj->IsJSObject()) {
5872 JSObject* obj = JSObject::cast(heap_obj);
5873 if (obj->map()->constructor() == constructor) {
5874 // Valid reference found add to instance array if supplied an update
5875 // count.
5876 if (instances != NULL && count < instances_size) {
5877 instances->set(count, obj);
5878 }
5879 count++;
5880 }
5881 }
5882 }
5883
5884 // Return the number of referencing objects found.
5885 return count;
5886}
5887
5888
5889// Scan the heap for objects constructed by a specific function.
5890// args[0]: the constructor to find instances of
5891// args[1]: the the maximum number of objects to return
5892static Object* Runtime_DebugConstructedBy(Arguments args) {
5893 ASSERT(args.length() == 2);
5894
5895 // First perform a full GC in order to avoid dead objects.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005896 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005897
5898 // Check parameters.
5899 CONVERT_CHECKED(JSFunction, constructor, args[0]);
5900 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
5901 RUNTIME_ASSERT(max_references >= 0);
5902
5903 // Get the number of referencing objects.
5904 int count;
5905 count = DebugConstructedBy(constructor, max_references, NULL, 0);
5906
5907 // Allocate an array to hold the result.
5908 Object* object = Heap::AllocateFixedArray(count);
5909 if (object->IsFailure()) return object;
5910 FixedArray* instances = FixedArray::cast(object);
5911
5912 // Fill the referencing objects.
5913 count = DebugConstructedBy(constructor, max_references, instances, count);
5914
5915 // Return result as JS array.
5916 Object* result =
5917 Heap::AllocateJSObject(
5918 Top::context()->global_context()->array_function());
5919 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
5920 return result;
5921}
5922
5923
ager@chromium.orgddb913d2009-01-27 10:01:48 +00005924// Find the effective prototype object as returned by __proto__.
5925// args[0]: the object to find the prototype for.
5926static Object* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005927 ASSERT(args.length() == 1);
5928
5929 CONVERT_CHECKED(JSObject, obj, args[0]);
5930
ager@chromium.orgddb913d2009-01-27 10:01:48 +00005931 // Use the __proto__ accessor.
5932 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005933}
5934
5935
5936static Object* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00005937 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005938 CPU::DebugBreak();
5939 return Heap::undefined_value();
5940}
5941
5942
5943// Finds the script object from the script data. NOTE: This operation uses
5944// heap traversal to find the function generated for the source position
5945// for the requested break point. For lazily compiled functions several heap
5946// traversals might be required rendering this operation as a rather slow
5947// operation. However for setting break points which is normally done through
5948// some kind of user interaction the performance is not crucial.
5949static Handle<Object> Runtime_GetScriptFromScriptName(
5950 Handle<String> script_name) {
5951 // Scan the heap for Script objects to find the script with the requested
5952 // script data.
5953 Handle<Script> script;
5954 HeapIterator iterator;
5955 while (script.is_null() && iterator.has_next()) {
5956 HeapObject* obj = iterator.next();
5957 // If a script is found check if it has the script data requested.
5958 if (obj->IsScript()) {
5959 if (Script::cast(obj)->name()->IsString()) {
5960 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
5961 script = Handle<Script>(Script::cast(obj));
5962 }
5963 }
5964 }
5965 }
5966
5967 // If no script with the requested script data is found return undefined.
5968 if (script.is_null()) return Factory::undefined_value();
5969
5970 // Return the script found.
5971 return GetScriptWrapper(script);
5972}
5973
5974
5975// Get the script object from script data. NOTE: Regarding performance
5976// see the NOTE for GetScriptFromScriptData.
5977// args[0]: script data for the script to find the source for
5978static Object* Runtime_GetScript(Arguments args) {
5979 HandleScope scope;
5980
5981 ASSERT(args.length() == 1);
5982
5983 CONVERT_CHECKED(String, script_name, args[0]);
5984
5985 // Find the requested script.
5986 Handle<Object> result =
5987 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
5988 return *result;
5989}
5990
5991
5992static Object* Runtime_FunctionGetAssemblerCode(Arguments args) {
5993#ifdef DEBUG
5994 HandleScope scope;
5995 ASSERT(args.length() == 1);
5996 // Get the function and make sure it is compiled.
5997 CONVERT_ARG_CHECKED(JSFunction, func, 0);
5998 if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) {
5999 return Failure::Exception();
6000 }
6001 func->code()->PrintLn();
6002#endif // DEBUG
6003 return Heap::undefined_value();
6004}
6005
6006
6007static Object* Runtime_Abort(Arguments args) {
6008 ASSERT(args.length() == 2);
6009 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
6010 Smi::cast(args[1])->value());
6011 Top::PrintStack();
6012 OS::Abort();
6013 UNREACHABLE();
6014 return NULL;
6015}
6016
6017
kasper.lund44510672008-07-25 07:37:58 +00006018#ifdef DEBUG
6019// ListNatives is ONLY used by the fuzz-natives.js in debug mode
6020// Exclude the code in release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006021static Object* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00006022 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006023 HandleScope scope;
6024 Handle<JSArray> result = Factory::NewJSArray(0);
6025 int index = 0;
6026#define ADD_ENTRY(Name, argc) \
6027 { \
6028 HandleScope inner; \
6029 Handle<String> name = \
6030 Factory::NewStringFromAscii(Vector<const char>(#Name, strlen(#Name))); \
6031 Handle<JSArray> pair = Factory::NewJSArray(0); \
6032 SetElement(pair, 0, name); \
6033 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
6034 SetElement(result, index++, pair); \
6035 }
6036 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
6037#undef ADD_ENTRY
6038 return *result;
6039}
kasper.lund44510672008-07-25 07:37:58 +00006040#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006041
6042
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006043static Object* Runtime_Log(Arguments args) {
6044 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +00006045 CONVERT_CHECKED(String, format, args[0]);
6046 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006047 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006048 Logger::LogRuntime(chars, elms);
6049 return Heap::undefined_value();
6050}
6051
6052
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053static Object* Runtime_IS_VAR(Arguments args) {
6054 UNREACHABLE(); // implemented as macro in the parser
6055 return NULL;
6056}
6057
6058
6059// ----------------------------------------------------------------------------
6060// Implementation of Runtime
6061
6062#define F(name, nargs) \
6063 { #name, "RuntimeStub_" #name, FUNCTION_ADDR(Runtime_##name), nargs, \
6064 static_cast<int>(Runtime::k##name) },
6065
6066static Runtime::Function Runtime_functions[] = {
6067 RUNTIME_FUNCTION_LIST(F)
6068 { NULL, NULL, NULL, 0, -1 }
6069};
6070
6071#undef F
6072
6073
6074Runtime::Function* Runtime::FunctionForId(FunctionId fid) {
6075 ASSERT(0 <= fid && fid < kNofFunctions);
6076 return &Runtime_functions[fid];
6077}
6078
6079
6080Runtime::Function* Runtime::FunctionForName(const char* name) {
6081 for (Function* f = Runtime_functions; f->name != NULL; f++) {
6082 if (strcmp(f->name, name) == 0) {
6083 return f;
6084 }
6085 }
6086 return NULL;
6087}
6088
6089
6090void Runtime::PerformGC(Object* result) {
6091 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006092 if (failure->IsRetryAfterGC()) {
6093 // Try to do a garbage collection; ignore it if it fails. The C
6094 // entry stub will throw an out-of-memory exception in that case.
6095 Heap::CollectGarbage(failure->requested(), failure->allocation_space());
6096 } else {
6097 // Handle last resort GC and make sure to allow future allocations
6098 // to grow the heap without causing GCs (if possible).
6099 Counters::gc_last_resort_from_js.Increment();
6100 Heap::CollectAllGarbage();
6101 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006102}
6103
6104
6105} } // namespace v8::internal