blob: c3918e634c0f060c49870744f6d4eb2def7a7d5c [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
72#define CONVERT_CHECKED(Type, name, obj) \
73 RUNTIME_ASSERT(obj->Is##Type()); \
74 Type* name = Type::cast(obj);
75
76#define CONVERT_ARG_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
78 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
83#define CONVERT_BOOLEAN_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsBoolean()); \
85 bool name = (obj)->IsTrue();
86
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000109// Assert that the given argument has a valid value for a StrictModeFlag
110// and store it in a StrictModeFlag variable with the given name.
111#define CONVERT_STRICT_MODE_ARG(name, index) \
112 ASSERT(args[index]->IsSmi()); \
113 ASSERT(args.smi_at(index) == kStrictMode || \
114 args.smi_at(index) == kNonStrictMode); \
115 StrictModeFlag name = \
116 static_cast<StrictModeFlag>(args.smi_at(index));
117
118
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000119MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
120 JSObject* boilerplate) {
121 StackLimitCheck check(isolate);
122 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000124 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000125 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000127 if (!maybe_result->ToObject(&result)) return maybe_result;
128 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000129 JSObject* copy = JSObject::cast(result);
130
131 // Deep copy local properties.
132 if (copy->HasFastProperties()) {
133 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000134 for (int i = 0; i < properties->length(); i++) {
135 Object* value = properties->get(i);
136 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000139 if (!maybe_result->ToObject(&result)) return maybe_result;
140 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000141 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000142 }
143 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000144 int nof = copy->map()->inobject_properties();
145 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000146 Object* value = copy->InObjectPropertyAt(i);
147 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000149 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000150 if (!maybe_result->ToObject(&result)) return maybe_result;
151 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 }
154 }
155 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000156 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000157 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 if (!maybe_result->ToObject(&result)) return maybe_result;
159 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000160 FixedArray* names = FixedArray::cast(result);
161 copy->GetLocalPropertyNames(names, 0);
162 for (int i = 0; i < names->length(); i++) {
163 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000164 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000165 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000166 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000167 // Only deep copy fields from the object literal expression.
168 // In particular, don't try to copy the length attribute of
169 // an array.
170 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000171 Object* value =
172 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000174 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000175 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000176 if (!maybe_result->ToObject(&result)) return maybe_result;
177 }
178 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000179 // Creating object copy for literals. No strict mode needed.
180 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000181 if (!maybe_result->ToObject(&result)) return maybe_result;
182 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000183 }
184 }
185 }
186
187 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000188 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000189 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000190 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000191 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000192 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000193 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 if (elements->map() == heap->fixed_cow_array_map()) {
195 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000196#ifdef DEBUG
197 for (int i = 0; i < elements->length(); i++) {
198 ASSERT(!elements->get(i)->IsJSObject());
199 }
200#endif
201 } else {
202 for (int i = 0; i < elements->length(); i++) {
203 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000204 ASSERT(value->IsSmi() ||
205 value->IsTheHole() ||
206 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000207 if (value->IsJSObject()) {
208 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000209 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
210 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000211 if (!maybe_result->ToObject(&result)) return maybe_result;
212 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000213 elements->set(i, result);
214 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000215 }
216 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000217 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000218 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000219 case DICTIONARY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000220 NumberDictionary* element_dictionary = copy->element_dictionary();
221 int capacity = element_dictionary->Capacity();
222 for (int i = 0; i < capacity; i++) {
223 Object* k = element_dictionary->KeyAt(i);
224 if (element_dictionary->IsKey(k)) {
225 Object* value = element_dictionary->ValueAt(i);
226 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000227 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000228 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
229 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000230 if (!maybe_result->ToObject(&result)) return maybe_result;
231 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000232 element_dictionary->ValueAtPut(i, result);
233 }
234 }
235 }
236 break;
237 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000238 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000239 UNIMPLEMENTED();
240 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000241 case EXTERNAL_PIXEL_ELEMENTS:
242 case EXTERNAL_BYTE_ELEMENTS:
243 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
244 case EXTERNAL_SHORT_ELEMENTS:
245 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
246 case EXTERNAL_INT_ELEMENTS:
247 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
248 case EXTERNAL_FLOAT_ELEMENTS:
249 case EXTERNAL_DOUBLE_ELEMENTS:
250 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000251 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000252 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000253 }
254 return copy;
255}
256
257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000258RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000259 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000260 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000261}
262
263
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000264RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000266 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000267}
268
269
ager@chromium.org236ad962008-09-25 09:45:57 +0000270static Handle<Map> ComputeObjectLiteralMap(
271 Handle<Context> context,
272 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000273 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000274 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000275 int properties_length = constant_properties->length();
276 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000277 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000278 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000279 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000280 for (int p = 0; p != properties_length; p += 2) {
281 Object* key = constant_properties->get(p);
282 uint32_t element_index = 0;
283 if (key->IsSymbol()) {
284 number_of_symbol_keys++;
285 } else if (key->ToArrayIndex(&element_index)) {
286 // An index key does not require space in the property backing store.
287 number_of_properties--;
288 } else {
289 // Bail out as a non-symbol non-index key makes caching impossible.
290 // ASSERT to make sure that the if condition after the loop is false.
291 ASSERT(number_of_symbol_keys != number_of_properties);
292 break;
293 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000294 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000295 // If we only have symbols and array indices among keys then we can
296 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000297 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000298 if ((number_of_symbol_keys == number_of_properties) &&
299 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000301 Handle<FixedArray> keys =
302 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000303 if (number_of_symbol_keys > 0) {
304 int index = 0;
305 for (int p = 0; p < properties_length; p += 2) {
306 Object* key = constant_properties->get(p);
307 if (key->IsSymbol()) {
308 keys->set(index++, key);
309 }
310 }
311 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000312 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000313 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000314 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000315 }
316 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000317 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000318 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000319 Handle<Map>(context->object_function()->initial_map()),
320 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000321}
322
323
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000324static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000325 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000326 Handle<FixedArray> literals,
327 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000328
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000329
330static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000332 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000333 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000334 bool should_have_fast_elements,
335 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000336 // Get the global context from the literals array. This is the
337 // context in which the function was created and we use the object
338 // function from this context to create the object literal. We do
339 // not use the object function from the current global context
340 // because this might be the object function from another context
341 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000342 Handle<Context> context =
343 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
344
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000345 // In case we have function literals, we want the object to be in
346 // slow properties mode for now. We don't go in the map cache because
347 // maps with constant functions can't be shared if the functions are
348 // not the same (which is the common case).
349 bool is_result_from_cache = false;
350 Handle<Map> map = has_function_literal
351 ? Handle<Map>(context->object_function()->initial_map())
352 : ComputeObjectLiteralMap(context,
353 constant_properties,
354 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000356 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000357
358 // Normalize the elements of the boilerplate to save space if needed.
359 if (!should_have_fast_elements) NormalizeElements(boilerplate);
360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 // Add the constant properties to the boilerplate.
362 int length = constant_properties->length();
363 bool should_transform =
364 !is_result_from_cache && boilerplate->HasFastProperties();
365 if (should_transform || has_function_literal) {
366 // Normalize the properties of object to avoid n^2 behavior
367 // when extending the object multiple properties. Indicate the number of
368 // properties to be added.
369 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
370 }
371
372 for (int index = 0; index < length; index +=2) {
373 Handle<Object> key(constant_properties->get(index+0), isolate);
374 Handle<Object> value(constant_properties->get(index+1), isolate);
375 if (value->IsFixedArray()) {
376 // The value contains the constant_properties of a
377 // simple object or array literal.
378 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
379 value = CreateLiteralBoilerplate(isolate, literals, array);
380 if (value.is_null()) return value;
381 }
382 Handle<Object> result;
383 uint32_t element_index = 0;
384 if (key->IsSymbol()) {
385 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
386 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000387 result = SetOwnElement(boilerplate,
388 element_index,
389 value,
390 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000392 Handle<String> name(String::cast(*key));
393 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000394 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
395 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 } else if (key->ToArrayIndex(&element_index)) {
398 // Array index (uint32).
399 result = SetOwnElement(boilerplate,
400 element_index,
401 value,
402 kNonStrictMode);
403 } else {
404 // Non-uint32 number.
405 ASSERT(key->IsNumber());
406 double num = key->Number();
407 char arr[100];
408 Vector<char> buffer(arr, ARRAY_SIZE(arr));
409 const char* str = DoubleToCString(num, buffer);
410 Handle<String> name =
411 isolate->factory()->NewStringFromAscii(CStrVector(str));
412 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
413 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 // If setting the property on the boilerplate throws an
416 // exception, the exception is converted to an empty handle in
417 // the handle based operations. In that case, we need to
418 // convert back to an exception.
419 if (result.is_null()) return result;
420 }
421
422 // Transform to fast properties if necessary. For object literals with
423 // containing function literals we defer this operation until after all
424 // computed properties have been assigned so that we can generate
425 // constant function properties.
426 if (should_transform && !has_function_literal) {
427 TransformToFastProperties(boilerplate,
428 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429 }
430
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000431 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000432}
433
434
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000435static const int kSmiOnlyLiteralMinimumLength = 1024;
436
437
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000439 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000440 Handle<FixedArray> literals,
441 Handle<FixedArray> elements) {
442 // Create the JSArray.
443 Handle<JSFunction> constructor(
444 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000445 Handle<JSArray> object =
446 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000447
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000448 ElementsKind constant_elements_kind =
449 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
450 Handle<FixedArrayBase> constant_elements_values(
451 FixedArrayBase::cast(elements->get(1)));
452
453 ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
454 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
455 bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
456 constant_elements_kind > object->GetElementsKind();
457
458 if (!FLAG_smi_only_arrays &&
459 constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
460 constant_elements_kind != object->GetElementsKind()) {
461 allow_literal_kind_transition = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000462 }
463
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000464 // If the ElementsKind of the constant values of the array literal are less
465 // specific than the ElementsKind of the boilerplate array object, change the
466 // boilerplate array object's map to reflect that kind.
467 if (allow_literal_kind_transition) {
468 Handle<Map> transitioned_array_map =
469 isolate->factory()->GetElementsTransitionMap(object,
470 constant_elements_kind);
471 object->set_map(*transitioned_array_map);
472 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000473
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000474 Handle<FixedArrayBase> copied_elements_values;
475 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
476 ASSERT(FLAG_smi_only_arrays);
477 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
478 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000479 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
481 constant_elements_kind == FAST_ELEMENTS);
482 const bool is_cow =
483 (constant_elements_values->map() ==
484 isolate->heap()->fixed_cow_array_map());
485 if (is_cow) {
486 copied_elements_values = constant_elements_values;
487#if DEBUG
488 Handle<FixedArray> fixed_array_values =
489 Handle<FixedArray>::cast(copied_elements_values);
490 for (int i = 0; i < fixed_array_values->length(); i++) {
491 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
492 }
493#endif
494 } else {
495 Handle<FixedArray> fixed_array_values =
496 Handle<FixedArray>::cast(constant_elements_values);
497 Handle<FixedArray> fixed_array_values_copy =
498 isolate->factory()->CopyFixedArray(fixed_array_values);
499 copied_elements_values = fixed_array_values_copy;
500 for (int i = 0; i < fixed_array_values->length(); i++) {
501 Object* current = fixed_array_values->get(i);
502 if (current->IsFixedArray()) {
503 // The value contains the constant_properties of a
504 // simple object or array literal.
505 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
506 Handle<Object> result =
507 CreateLiteralBoilerplate(isolate, literals, fa);
508 if (result.is_null()) return result;
509 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000510 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000511 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000512 }
513 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000514 object->set_elements(*copied_elements_values);
515 object->set_length(Smi::FromInt(copied_elements_values->length()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000516 return object;
517}
518
519
520static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000522 Handle<FixedArray> literals,
523 Handle<FixedArray> array) {
524 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000526 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000527 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 return CreateObjectLiteralBoilerplate(isolate,
529 literals,
530 elements,
531 true,
532 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000533 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 return CreateObjectLiteralBoilerplate(isolate,
535 literals,
536 elements,
537 false,
538 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000540 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000541 default:
542 UNREACHABLE();
543 return Handle<Object>::null();
544 }
545}
546
547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000548RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000549 // Takes a FixedArray of elements containing the literal elements of
550 // the array literal and produces JSArray with those elements.
551 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000552 // which contains the context from which to get the Array function
553 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000554 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000555 ASSERT(args.length() == 3);
556 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000557 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000558 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 Handle<Object> object =
561 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000562 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000564 // Update the functions literal and return the boilerplate.
565 literals->set(literals_index, *object);
566 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000567}
568
569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000570RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000572 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000573 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000574 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000576 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
578 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000579
580 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000581 Handle<Object> boilerplate(literals->get(literals_index), isolate);
582 if (*boilerplate == isolate->heap()->undefined_value()) {
583 boilerplate = CreateObjectLiteralBoilerplate(isolate,
584 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000585 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 should_have_fast_elements,
587 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000588 if (boilerplate.is_null()) return Failure::Exception();
589 // Update the functions literal and return the boilerplate.
590 literals->set(literals_index, *boilerplate);
591 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000592 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000593}
594
595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000596RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000598 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000599 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000600 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000601 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000602 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000603 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
604 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000605
606 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000607 Handle<Object> boilerplate(literals->get(literals_index), isolate);
608 if (*boilerplate == isolate->heap()->undefined_value()) {
609 boilerplate = CreateObjectLiteralBoilerplate(isolate,
610 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000611 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000612 should_have_fast_elements,
613 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000614 if (boilerplate.is_null()) return Failure::Exception();
615 // Update the functions literal and return the boilerplate.
616 literals->set(literals_index, *boilerplate);
617 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000619}
620
621
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000622RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000623 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000624 ASSERT(args.length() == 3);
625 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000626 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000627 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
628
629 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000630 Handle<Object> boilerplate(literals->get(literals_index), isolate);
631 if (*boilerplate == isolate->heap()->undefined_value()) {
632 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000633 if (boilerplate.is_null()) return Failure::Exception();
634 // Update the functions literal and return the boilerplate.
635 literals->set(literals_index, *boilerplate);
636 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000637 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000638}
639
640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000641RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000642 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000643 ASSERT(args.length() == 3);
644 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000645 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000646 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
647
648 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000649 Handle<Object> boilerplate(literals->get(literals_index), isolate);
650 if (*boilerplate == isolate->heap()->undefined_value()) {
651 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000652 if (boilerplate.is_null()) return Failure::Exception();
653 // Update the functions literal and return the boilerplate.
654 literals->set(literals_index, *boilerplate);
655 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000656 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000657 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000658 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000659 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000660 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000661}
662
663
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
665 ASSERT(args.length() == 2);
666 Object* handler = args[0];
667 Object* prototype = args[1];
668 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000670 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
671}
672
673
lrn@chromium.org34e60782011-09-15 07:25:40 +0000674RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
675 ASSERT(args.length() == 4);
676 Object* handler = args[0];
677 Object* call_trap = args[1];
678 Object* construct_trap = args[2];
679 Object* prototype = args[3];
680 Object* used_prototype =
681 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
682 return isolate->heap()->AllocateJSFunctionProxy(
683 handler, call_trap, construct_trap, used_prototype);
684}
685
686
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000687RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
688 ASSERT(args.length() == 1);
689 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000690 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000691}
692
693
lrn@chromium.org34e60782011-09-15 07:25:40 +0000694RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
695 ASSERT(args.length() == 1);
696 Object* obj = args[0];
697 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
698}
699
700
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000701RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
702 ASSERT(args.length() == 1);
703 CONVERT_CHECKED(JSProxy, proxy, args[0]);
704 return proxy->handler();
705}
706
707
lrn@chromium.org34e60782011-09-15 07:25:40 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
709 ASSERT(args.length() == 1);
710 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
711 return proxy->call_trap();
712}
713
714
715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
716 ASSERT(args.length() == 1);
717 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
718 return proxy->construct_trap();
719}
720
721
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
723 ASSERT(args.length() == 1);
724 CONVERT_CHECKED(JSProxy, proxy, args[0]);
725 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000726 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000727}
728
729
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 1);
733 CONVERT_ARG_CHECKED(JSSet, holder, 0);
734 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
735 holder->set_table(*table);
736 return *holder;
737}
738
739
740RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
741 HandleScope scope(isolate);
742 ASSERT(args.length() == 2);
743 CONVERT_ARG_CHECKED(JSSet, holder, 0);
744 Handle<Object> key(args[1]);
745 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
746 table = ObjectHashSetAdd(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 2);
755 CONVERT_ARG_CHECKED(JSSet, holder, 0);
756 Handle<Object> key(args[1]);
757 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
758 return isolate->heap()->ToBoolean(table->Contains(*key));
759}
760
761
762RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
765 CONVERT_ARG_CHECKED(JSSet, holder, 0);
766 Handle<Object> key(args[1]);
767 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
768 table = ObjectHashSetRemove(table, key);
769 holder->set_table(*table);
770 return isolate->heap()->undefined_symbol();
771}
772
773
774RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
775 HandleScope scope(isolate);
776 ASSERT(args.length() == 1);
777 CONVERT_ARG_CHECKED(JSMap, holder, 0);
778 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
779 holder->set_table(*table);
780 return *holder;
781}
782
783
784RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 2);
787 CONVERT_ARG_CHECKED(JSMap, holder, 0);
788 Handle<Object> key(args[1]);
789 return ObjectHashTable::cast(holder->table())->Lookup(*key);
790}
791
792
793RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
794 HandleScope scope(isolate);
795 ASSERT(args.length() == 3);
796 CONVERT_ARG_CHECKED(JSMap, holder, 0);
797 Handle<Object> key(args[1]);
798 Handle<Object> value(args[2]);
799 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
800 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
801 holder->set_table(*new_table);
802 return *value;
803}
804
805
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000806RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
807 HandleScope scope(isolate);
808 ASSERT(args.length() == 1);
809 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
810 ASSERT(weakmap->map()->inobject_properties() == 0);
811 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
812 weakmap->set_table(*table);
813 weakmap->set_next(Smi::FromInt(0));
814 return *weakmap;
815}
816
817
818RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
819 NoHandleAllocation ha;
820 ASSERT(args.length() == 2);
821 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000822 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
823 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000824}
825
826
827RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
828 HandleScope scope(isolate);
829 ASSERT(args.length() == 3);
830 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000831 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000832 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000833 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000834 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
835 weakmap->set_table(*new_table);
836 return *value;
837}
838
839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000840RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000841 NoHandleAllocation ha;
842 ASSERT(args.length() == 1);
843 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 return JSObject::cast(obj)->class_name();
846}
847
ager@chromium.org7c537e22008-10-16 08:43:32 +0000848
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000849RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
850 NoHandleAllocation ha;
851 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000852 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
853 Object* obj = input_obj;
854 // We don't expect access checks to be needed on JSProxy objects.
855 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000856 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000857 if (obj->IsAccessCheckNeeded() &&
858 !isolate->MayNamedAccess(JSObject::cast(obj),
859 isolate->heap()->Proto_symbol(),
860 v8::ACCESS_GET)) {
861 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
862 return isolate->heap()->undefined_value();
863 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000864 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000865 } while (obj->IsJSObject() &&
866 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000867 return obj;
868}
869
870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000871RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000872 NoHandleAllocation ha;
873 ASSERT(args.length() == 2);
874 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
875 Object* O = args[0];
876 Object* V = args[1];
877 while (true) {
878 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000879 if (prototype->IsNull()) return isolate->heap()->false_value();
880 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881 V = prototype;
882 }
883}
884
885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000886RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000887 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000888 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000889 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000890 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891}
892
893
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000894// Recursively traverses hidden prototypes if property is not found
895static void GetOwnPropertyImplementation(JSObject* obj,
896 String* name,
897 LookupResult* result) {
898 obj->LocalLookupRealNamedProperty(name, result);
899
900 if (!result->IsProperty()) {
901 Object* proto = obj->GetPrototype();
902 if (proto->IsJSObject() &&
903 JSObject::cast(proto)->map()->is_hidden_prototype())
904 GetOwnPropertyImplementation(JSObject::cast(proto),
905 name, result);
906 }
907}
908
909
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000910static bool CheckAccessException(LookupResult* result,
911 v8::AccessType access_type) {
912 if (result->type() == CALLBACKS) {
913 Object* callback = result->GetCallbackObject();
914 if (callback->IsAccessorInfo()) {
915 AccessorInfo* info = AccessorInfo::cast(callback);
916 bool can_access =
917 (access_type == v8::ACCESS_HAS &&
918 (info->all_can_read() || info->all_can_write())) ||
919 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
920 (access_type == v8::ACCESS_SET && info->all_can_write());
921 return can_access;
922 }
923 }
924
925 return false;
926}
927
928
929static bool CheckAccess(JSObject* obj,
930 String* name,
931 LookupResult* result,
932 v8::AccessType access_type) {
933 ASSERT(result->IsProperty());
934
935 JSObject* holder = result->holder();
936 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000937 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000938 while (true) {
939 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000940 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000941 // Access check callback denied the access, but some properties
942 // can have a special permissions which override callbacks descision
943 // (currently see v8::AccessControl).
944 break;
945 }
946
947 if (current == holder) {
948 return true;
949 }
950
951 current = JSObject::cast(current->GetPrototype());
952 }
953
954 // API callbacks can have per callback access exceptions.
955 switch (result->type()) {
956 case CALLBACKS: {
957 if (CheckAccessException(result, access_type)) {
958 return true;
959 }
960 break;
961 }
962 case INTERCEPTOR: {
963 // If the object has an interceptor, try real named properties.
964 // Overwrite the result to fetch the correct property later.
965 holder->LookupRealNamedProperty(name, result);
966 if (result->IsProperty()) {
967 if (CheckAccessException(result, access_type)) {
968 return true;
969 }
970 }
971 break;
972 }
973 default:
974 break;
975 }
976
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000977 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000978 return false;
979}
980
981
982// TODO(1095): we should traverse hidden prototype hierachy as well.
983static bool CheckElementAccess(JSObject* obj,
984 uint32_t index,
985 v8::AccessType access_type) {
986 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000987 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000988 return false;
989 }
990
991 return true;
992}
993
994
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000995// Enumerator used as indices into the array returned from GetOwnProperty
996enum PropertyDescriptorIndices {
997 IS_ACCESSOR_INDEX,
998 VALUE_INDEX,
999 GETTER_INDEX,
1000 SETTER_INDEX,
1001 WRITABLE_INDEX,
1002 ENUMERABLE_INDEX,
1003 CONFIGURABLE_INDEX,
1004 DESCRIPTOR_SIZE
1005};
1006
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001007// Returns an array with the property description:
1008// if args[1] is not a property on args[0]
1009// returns undefined
1010// if args[1] is a data property on args[0]
1011// [false, value, Writeable, Enumerable, Configurable]
1012// if args[1] is an accessor on args[0]
1013// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001014RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001015 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001016 Heap* heap = isolate->heap();
1017 HandleScope scope(isolate);
1018 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1019 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001020 LookupResult result(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001021 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1022 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001023
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001024 // This could be an element.
1025 uint32_t index;
1026 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001027 switch (obj->HasLocalElement(index)) {
1028 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001029 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001030
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001031 case JSObject::STRING_CHARACTER_ELEMENT: {
1032 // Special handling of string objects according to ECMAScript 5
1033 // 15.5.5.2. Note that this might be a string object with elements
1034 // other than the actual string value. This is covered by the
1035 // subsequent cases.
1036 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1037 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001038 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001039
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001040 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001041 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001042 elms->set(WRITABLE_INDEX, heap->false_value());
1043 elms->set(ENUMERABLE_INDEX, heap->false_value());
1044 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001045 return *desc;
1046 }
1047
1048 case JSObject::INTERCEPTED_ELEMENT:
1049 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001050 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001051 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001052 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001053 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001054 elms->set(WRITABLE_INDEX, heap->true_value());
1055 elms->set(ENUMERABLE_INDEX, heap->true_value());
1056 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001057 return *desc;
1058 }
1059
1060 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001061 Handle<JSObject> holder = obj;
1062 if (obj->IsJSGlobalProxy()) {
1063 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001064 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001065 ASSERT(proto->IsJSGlobalObject());
1066 holder = Handle<JSObject>(JSObject::cast(proto));
1067 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001068 FixedArray* elements = FixedArray::cast(holder->elements());
1069 NumberDictionary* dictionary = NULL;
1070 if (elements->map() == heap->non_strict_arguments_elements_map()) {
1071 dictionary = NumberDictionary::cast(elements->get(1));
1072 } else {
1073 dictionary = NumberDictionary::cast(elements);
1074 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001075 int entry = dictionary->FindEntry(index);
1076 ASSERT(entry != NumberDictionary::kNotFound);
1077 PropertyDetails details = dictionary->DetailsAt(entry);
1078 switch (details.type()) {
1079 case CALLBACKS: {
1080 // This is an accessor property with getter and/or setter.
1081 FixedArray* callbacks =
1082 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001083 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001084 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
1085 elms->set(GETTER_INDEX, callbacks->get(0));
1086 }
1087 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
1088 elms->set(SETTER_INDEX, callbacks->get(1));
1089 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001090 break;
1091 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001092 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001093 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001094 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001095 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001096 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001097 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001098 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001099 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001100 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001101 default:
1102 UNREACHABLE();
1103 break;
1104 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001105 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1106 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001107 return *desc;
1108 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001109 }
1110 }
1111
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001112 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001113 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001114
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001115 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001116 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001117 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001118
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001119 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001120 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001121 }
1122
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001123 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1124 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001125
1126 bool is_js_accessor = (result.type() == CALLBACKS) &&
1127 (result.GetCallbackObject()->IsFixedArray());
1128
1129 if (is_js_accessor) {
1130 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001131 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001132
1133 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1134 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1135 elms->set(GETTER_INDEX, structure->get(0));
1136 }
1137 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1138 elms->set(SETTER_INDEX, structure->get(1));
1139 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001140 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001141 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1142 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001143
1144 PropertyAttributes attrs;
1145 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001146 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001147 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1148 if (!maybe_value->ToObject(&value)) return maybe_value;
1149 }
1150 elms->set(VALUE_INDEX, value);
1151 }
1152
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001153 return *desc;
1154}
1155
1156
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001157RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001158 ASSERT(args.length() == 1);
1159 CONVERT_CHECKED(JSObject, obj, args[0]);
1160 return obj->PreventExtensions();
1161}
1162
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001164RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001165 ASSERT(args.length() == 1);
1166 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001167 if (obj->IsJSGlobalProxy()) {
1168 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001169 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001170 ASSERT(proto->IsJSGlobalObject());
1171 obj = JSObject::cast(proto);
1172 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001173 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001174}
1175
1176
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001177RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001178 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001180 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1181 CONVERT_ARG_CHECKED(String, pattern, 1);
1182 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001183 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1184 if (result.is_null()) return Failure::Exception();
1185 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001186}
1187
1188
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001189RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001190 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001191 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001192 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001193 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001194}
1195
1196
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001197RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001198 ASSERT(args.length() == 1);
1199 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001200 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001201 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001202}
1203
1204
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001205RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001206 ASSERT(args.length() == 2);
1207 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001208 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001209 int index = field->value();
1210 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1211 InstanceType type = templ->map()->instance_type();
1212 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1213 type == OBJECT_TEMPLATE_INFO_TYPE);
1214 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001215 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001216 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1217 } else {
1218 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1219 }
1220 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001221}
1222
1223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001224RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001225 ASSERT(args.length() == 1);
1226 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001227 Map* old_map = object->map();
1228 bool needs_access_checks = old_map->is_access_check_needed();
1229 if (needs_access_checks) {
1230 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001231 Object* new_map;
1232 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1233 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1234 }
ager@chromium.org32912102009-01-16 10:38:43 +00001235
1236 Map::cast(new_map)->set_is_access_check_needed(false);
1237 object->set_map(Map::cast(new_map));
1238 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001239 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001240}
1241
1242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001243RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001244 ASSERT(args.length() == 1);
1245 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001246 Map* old_map = object->map();
1247 if (!old_map->is_access_check_needed()) {
1248 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001249 Object* new_map;
1250 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1251 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1252 }
ager@chromium.org32912102009-01-16 10:38:43 +00001253
1254 Map::cast(new_map)->set_is_access_check_needed(true);
1255 object->set_map(Map::cast(new_map));
1256 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001257 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001258}
1259
1260
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001261static Failure* ThrowRedeclarationError(Isolate* isolate,
1262 const char* type,
1263 Handle<String> name) {
1264 HandleScope scope(isolate);
1265 Handle<Object> type_handle =
1266 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267 Handle<Object> args[2] = { type_handle, name };
1268 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001269 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1270 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001271}
1272
1273
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001274RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001275 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001276 HandleScope scope(isolate);
1277 Handle<GlobalObject> global = Handle<GlobalObject>(
1278 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001279
ager@chromium.org3811b432009-10-28 14:53:37 +00001280 Handle<Context> context = args.at<Context>(0);
1281 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001282 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284 // Traverse the name/value pairs and set the properties.
1285 int length = pairs->length();
1286 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001287 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001289 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290
1291 // We have to declare a global const property. To capture we only
1292 // assign to it when evaluating the assignment for "const x =
1293 // <expr>" the initial value is the hole.
1294 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001295 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296 if (value->IsUndefined() || is_const_property) {
1297 // Lookup the property in the global object, and don't set the
1298 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001299 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300 global->Lookup(*name, &lookup);
1301 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001302 // We found an existing property. Unless it was an interceptor
1303 // that claims the property is absent, skip this declaration.
1304 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 continue;
1306 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001307 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1308 if (attributes != ABSENT) {
1309 continue;
1310 }
1311 // Fall-through and introduce the absent property by using
1312 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001313 }
1314 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001315 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001317 Handle<SharedFunctionInfo> shared =
1318 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001320 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1321 context,
1322 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001323 value = function;
1324 }
1325
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001326 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327 global->LocalLookup(*name, &lookup);
1328
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001329 // Compute the property attributes. According to ECMA-262, section
1330 // 13, page 71, the property must be read-only and
1331 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1332 // property as read-only, so we don't either.
1333 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001334 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001335 attr |= DONT_DELETE;
1336 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001337 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001338 if (is_const_property || (is_native && is_function_declaration)) {
1339 attr |= READ_ONLY;
1340 }
1341
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001342 // Safari does not allow the invocation of callback setters for
1343 // function declarations. To mimic this behavior, we do not allow
1344 // the invocation of setters for function values. This makes a
1345 // difference for global functions with the same names as event
1346 // handlers such as "function onload() {}". Firefox does call the
1347 // onload setter in those case and Safari does not. We follow
1348 // Safari for compatibility.
1349 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001350 // Do not change DONT_DELETE to false from true.
1351 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001352 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001353 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001354 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001356 RETURN_IF_EMPTY_HANDLE(isolate,
1357 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001358 name,
1359 value,
1360 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001362 StrictModeFlag strict_mode = DeclareGlobalsStrictModeFlag::decode(flags);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001363 RETURN_IF_EMPTY_HANDLE(isolate,
1364 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001365 name,
1366 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001367 static_cast<PropertyAttributes>(attr),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001368 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369 }
1370 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001371
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001372 ASSERT(!isolate->has_pending_exception());
1373 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001374}
1375
1376
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001377RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001378 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001379 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001380
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001381 // Declarations are always made in a function or global context. In the
1382 // case of eval code, the context passed is the context of the caller,
1383 // which may be some nested context and not the declaration context.
1384 RUNTIME_ASSERT(args[0]->IsContext());
1385 Handle<Context> context(Context::cast(args[0])->declaration_context());
1386
ager@chromium.org7c537e22008-10-16 08:43:32 +00001387 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001388 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001389 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001390 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001391
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001392 int index;
1393 PropertyAttributes attributes;
1394 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001395 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001396 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001397 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398
1399 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001400 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001401 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1402 // Functions are not read-only.
1403 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1404 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001405 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406 }
1407
1408 // Initialize it if necessary.
1409 if (*initial_value != NULL) {
1410 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001411 ASSERT(holder.is_identical_to(context));
1412 if (((attributes & READ_ONLY) == 0) ||
1413 context->get(index)->IsTheHole()) {
1414 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415 }
1416 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001417 // Slow case: The property is in the context extension object of a
1418 // function context or the global object of a global context.
1419 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001420 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001421 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001422 SetProperty(object, name, initial_value, mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001423 }
1424 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001426 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001427 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001428 // "declared" in the function context's extension context or as a
1429 // property of the the global object.
1430 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001431 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001432 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001433 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001434 // Context extension objects are allocated lazily.
1435 ASSERT(context->IsFunctionContext());
1436 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001437 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001438 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001439 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001440 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001441
ager@chromium.org7c537e22008-10-16 08:43:32 +00001442 // Declare the property by setting it to the initial value if provided,
1443 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1444 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001445 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001446 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001447 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001448 // Declaring a const context slot is a conflicting declaration if
1449 // there is a callback with that name in a prototype. It is
1450 // allowed to introduce const variables in
1451 // JSContextExtensionObjects. They are treated specially in
1452 // SetProperty and no setters are invoked for those since they are
1453 // not real JSObjects.
1454 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001455 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001456 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001457 object->Lookup(*name, &lookup);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001458 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001459 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001460 }
1461 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001462 RETURN_IF_EMPTY_HANDLE(isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001463 SetProperty(object, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001464 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001465 }
1466
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001467 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001468}
1469
1470
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001471RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001473 // args[0] == name
1474 // args[1] == strict_mode
1475 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001476
1477 // Determine if we need to assign to the variable if it already
1478 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001479 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1480 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001481
1482 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001483 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001484 RUNTIME_ASSERT(args[1]->IsSmi());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001485 CONVERT_STRICT_MODE_ARG(strict_mode, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001486
1487 // According to ECMA-262, section 12.2, page 62, the property must
1488 // not be deletable.
1489 PropertyAttributes attributes = DONT_DELETE;
1490
1491 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001492 // there, there is a property with this name in the prototype chain.
1493 // We follow Safari and Firefox behavior and only set the property
1494 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001495 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001496 // Note that objects can have hidden prototypes, so we need to traverse
1497 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001498 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001499 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001500 while (object->IsJSObject() &&
1501 JSObject::cast(object)->map()->is_hidden_prototype()) {
1502 JSObject* raw_holder = JSObject::cast(object);
1503 raw_holder->LocalLookup(*name, &lookup);
1504 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1505 HandleScope handle_scope(isolate);
1506 Handle<JSObject> holder(raw_holder);
1507 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1508 // Update the raw pointer in case it's changed due to GC.
1509 raw_holder = *holder;
1510 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1511 // Found an interceptor that's not read only.
1512 if (assign) {
1513 return raw_holder->SetProperty(
1514 &lookup, *name, args[2], attributes, strict_mode);
1515 } else {
1516 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001517 }
1518 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001519 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001520 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001521 }
1522
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001523 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001524 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001525 if (assign) {
1526 return global->SetProperty(*name, args[2], attributes, strict_mode);
1527 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001528 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529}
1530
1531
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001532RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001533 // All constants are declared with an initial value. The name
1534 // of the constant is the first argument and the initial value
1535 // is the second.
1536 RUNTIME_ASSERT(args.length() == 2);
1537 CONVERT_ARG_CHECKED(String, name, 0);
1538 Handle<Object> value = args.at<Object>(1);
1539
1540 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001541 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542
1543 // According to ECMA-262, section 12.2, page 62, the property must
1544 // not be deletable. Since it's a const, it must be READ_ONLY too.
1545 PropertyAttributes attributes =
1546 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1547
1548 // Lookup the property locally in the global object. If it isn't
1549 // there, we add the property and take special precautions to always
1550 // add it as a local property even in case of callbacks in the
1551 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001552 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001553 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001554 global->LocalLookup(*name, &lookup);
1555 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001556 return global->SetLocalPropertyIgnoreAttributes(*name,
1557 *value,
1558 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001559 }
1560
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001563 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001564 HandleScope handle_scope(isolate);
1565 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001566
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001567 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 // property through an interceptor and only do it if it's
1569 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001570 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001571 RETURN_IF_EMPTY_HANDLE(isolate,
1572 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001573 name,
1574 value,
1575 attributes,
1576 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001577 return *value;
1578 }
1579
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001580 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581 // constant. For now, we determine this by checking if the
1582 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001583 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001584 PropertyType type = lookup.type();
1585 if (type == FIELD) {
1586 FixedArray* properties = global->properties();
1587 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001588 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001589 properties->set(index, *value);
1590 }
1591 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001592 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1593 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001594 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595 }
1596 } else {
1597 // Ignore re-initialization of constants that have already been
1598 // assigned a function value.
1599 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1600 }
1601
1602 // Use the set value as the result of the operation.
1603 return *value;
1604}
1605
1606
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001607RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001608 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001609 ASSERT(args.length() == 3);
1610
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001611 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001614 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001615 RUNTIME_ASSERT(args[1]->IsContext());
1616 Handle<Context> context(Context::cast(args[1])->declaration_context());
1617
1618 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001619
1620 int index;
1621 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001622 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001623 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001624 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001625 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001628 ASSERT(holder->IsContext());
1629 // Property was found in a context. Perform the assignment if we
1630 // found some non-constant or an uninitialized constant.
1631 Handle<Context> context = Handle<Context>::cast(holder);
1632 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1633 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001634 }
1635 return *value;
1636 }
1637
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001638 // The property could not be found, we introduce it as a property of the
1639 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001640 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001641 Handle<JSObject> global = Handle<JSObject>(
1642 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001643 // Strict mode not needed (const disallowed in strict mode).
1644 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001646 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001647 return *value;
1648 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001649
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001650 // The property was present in some function's context extension object,
1651 // as a property on the subject of a with, or as a property of the global
1652 // object.
1653 //
1654 // In most situations, eval-introduced consts should still be present in
1655 // the context extension object. However, because declaration and
1656 // initialization are separate, the property might have been deleted
1657 // before we reach the initialization point.
1658 //
1659 // Example:
1660 //
1661 // function f() { eval("delete x; const x;"); }
1662 //
1663 // In that case, the initialization behaves like a normal assignment.
1664 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001665
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001666 if (*object == context->extension()) {
1667 // This is the property that was introduced by the const declaration.
1668 // Set it if it hasn't been set before. NOTE: We cannot use
1669 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001670 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001671 object->LocalLookupRealNamedProperty(*name, &lookup);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001672 ASSERT(lookup.IsProperty()); // the property was declared
1673 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1674
1675 PropertyType type = lookup.type();
1676 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001677 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001678 int index = lookup.GetFieldIndex();
1679 if (properties->get(index)->IsTheHole()) {
1680 properties->set(index, *value);
1681 }
1682 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001683 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1684 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001685 }
1686 } else {
1687 // We should not reach here. Any real, named property should be
1688 // either a field or a dictionary slot.
1689 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001690 }
1691 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001692 // The property was found on some other object. Set it if it is not a
1693 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001694 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001695 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001696 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001697 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001698 SetProperty(object, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001699 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001700 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001701
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702 return *value;
1703}
1704
1705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001706RUNTIME_FUNCTION(MaybeObject*,
1707 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001708 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001709 ASSERT(args.length() == 2);
1710 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001711 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001712 if (object->HasFastProperties()) {
1713 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1714 }
1715 return *object;
1716}
1717
1718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001719RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001720 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001721 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001722 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1723 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001724 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001725 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001726 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001727 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001728 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001729 RUNTIME_ASSERT(index >= 0);
1730 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001732 Handle<Object> result = RegExpImpl::Exec(regexp,
1733 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001734 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001735 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001736 if (result.is_null()) return Failure::Exception();
1737 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001738}
1739
1740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001741RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001742 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001743 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001744 if (elements_count < 0 ||
1745 elements_count > FixedArray::kMaxLength ||
1746 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001748 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001749 Object* new_object;
1750 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001752 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1753 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001754 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1756 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001757 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1758 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001759 {
1760 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001761 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001762 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001764 }
1765 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001767 array->set_elements(elements);
1768 array->set_length(Smi::FromInt(elements_count));
1769 // Write in-object properties after the length of the array.
1770 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1771 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1772 return array;
1773}
1774
1775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001776RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001777 AssertNoAllocation no_alloc;
1778 ASSERT(args.length() == 5);
1779 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1780 CONVERT_CHECKED(String, source, args[1]);
1781
1782 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001783 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001784
1785 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001786 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001787
1788 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001789 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001790
1791 Map* map = regexp->map();
1792 Object* constructor = map->constructor();
1793 if (constructor->IsJSFunction() &&
1794 JSFunction::cast(constructor)->initial_map() == map) {
1795 // If we still have the original map, set in-object properties directly.
1796 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001797 // Both true and false are immovable immortal objects so no need for write
1798 // barrier.
1799 regexp->InObjectPropertyAtPut(
1800 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1801 regexp->InObjectPropertyAtPut(
1802 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1803 regexp->InObjectPropertyAtPut(
1804 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001805 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1806 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001807 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001808 return regexp;
1809 }
1810
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001811 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001812 PropertyAttributes final =
1813 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1814 PropertyAttributes writable =
1815 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001817 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001818 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001819 source,
1820 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001821 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001822 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001823 global,
1824 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001825 ASSERT(!result->IsFailure());
1826 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001827 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001828 ignoreCase,
1829 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001830 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001831 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001832 multiline,
1833 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001834 ASSERT(!result->IsFailure());
1835 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001837 Smi::FromInt(0),
1838 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001839 ASSERT(!result->IsFailure());
1840 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001841 return regexp;
1842}
1843
1844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001845RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001846 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001847 ASSERT(args.length() == 1);
1848 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1849 // This is necessary to enable fast checks for absence of elements
1850 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001851 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001852 return Smi::FromInt(0);
1853}
1854
1855
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001856static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1857 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001858 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001859 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001860 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1861 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1862 Handle<JSFunction> optimized =
1863 isolate->factory()->NewFunction(key,
1864 JS_OBJECT_TYPE,
1865 JSObject::kHeaderSize,
1866 code,
1867 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001868 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001869 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001870 return optimized;
1871}
1872
1873
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001874RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001875 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001876 ASSERT(args.length() == 1);
1877 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1878
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001879 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1880 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1881 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1882 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1883 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1884 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1885 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001886
1887 return *holder;
1888}
1889
1890
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001891RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1892 NoHandleAllocation handle_free;
1893 ASSERT(args.length() == 1);
1894 CONVERT_CHECKED(JSFunction, function, args[0]);
1895 SharedFunctionInfo* shared = function->shared();
1896 if (shared->native() || shared->strict_mode()) {
1897 return isolate->heap()->undefined_value();
1898 }
1899 // Returns undefined for strict or native functions, or
1900 // the associated global receiver for "normal" functions.
1901
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001902 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001903 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001904 return global_context->global()->global_receiver();
1905}
1906
1907
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001908RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001909 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001910 ASSERT(args.length() == 4);
1911 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001912 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001913 Handle<String> pattern = args.at<String>(2);
1914 Handle<String> flags = args.at<String>(3);
1915
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001916 // Get the RegExp function from the context in the literals array.
1917 // This is the RegExp function from the context in which the
1918 // function was created. We do not use the RegExp function from the
1919 // current global context because this might be the RegExp function
1920 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001921 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001922 Handle<JSFunction>(
1923 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001924 // Compute the regular expression literal.
1925 bool has_pending_exception;
1926 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001927 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1928 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001930 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001931 return Failure::Exception();
1932 }
1933 literals->set(index, *regexp);
1934 return *regexp;
1935}
1936
1937
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001938RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001939 NoHandleAllocation ha;
1940 ASSERT(args.length() == 1);
1941
1942 CONVERT_CHECKED(JSFunction, f, args[0]);
1943 return f->shared()->name();
1944}
1945
1946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001947RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001948 NoHandleAllocation ha;
1949 ASSERT(args.length() == 2);
1950
1951 CONVERT_CHECKED(JSFunction, f, args[0]);
1952 CONVERT_CHECKED(String, name, args[1]);
1953 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001954 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001955}
1956
1957
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001958RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1959 NoHandleAllocation ha;
1960 ASSERT(args.length() == 1);
1961 CONVERT_CHECKED(JSFunction, f, args[0]);
1962 return isolate->heap()->ToBoolean(
1963 f->shared()->name_should_print_as_anonymous());
1964}
1965
1966
1967RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1968 NoHandleAllocation ha;
1969 ASSERT(args.length() == 1);
1970 CONVERT_CHECKED(JSFunction, f, args[0]);
1971 f->shared()->set_name_should_print_as_anonymous(true);
1972 return isolate->heap()->undefined_value();
1973}
1974
1975
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001976RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001977 NoHandleAllocation ha;
1978 ASSERT(args.length() == 1);
1979
1980 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001981 Object* obj = f->RemovePrototype();
1982 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001983
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001984 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001985}
1986
1987
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001988RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001989 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001990 ASSERT(args.length() == 1);
1991
1992 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001993 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1994 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001995
1996 return *GetScriptWrapper(Handle<Script>::cast(script));
1997}
1998
1999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002000RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002001 NoHandleAllocation ha;
2002 ASSERT(args.length() == 1);
2003
2004 CONVERT_CHECKED(JSFunction, f, args[0]);
2005 return f->shared()->GetSourceCode();
2006}
2007
2008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002009RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002010 NoHandleAllocation ha;
2011 ASSERT(args.length() == 1);
2012
2013 CONVERT_CHECKED(JSFunction, fun, args[0]);
2014 int pos = fun->shared()->start_position();
2015 return Smi::FromInt(pos);
2016}
2017
2018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002019RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002020 ASSERT(args.length() == 2);
2021
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002022 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002023 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2024
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002025 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2026
2027 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002028 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002029}
2030
2031
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002032RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002033 NoHandleAllocation ha;
2034 ASSERT(args.length() == 2);
2035
2036 CONVERT_CHECKED(JSFunction, fun, args[0]);
2037 CONVERT_CHECKED(String, name, args[1]);
2038 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002039 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002040}
2041
2042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002043RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 NoHandleAllocation ha;
2045 ASSERT(args.length() == 2);
2046
2047 CONVERT_CHECKED(JSFunction, fun, args[0]);
2048 CONVERT_CHECKED(Smi, length, args[1]);
2049 fun->shared()->set_length(length->value());
2050 return length;
2051}
2052
2053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002054RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002055 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002056 ASSERT(args.length() == 2);
2057
2058 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002059 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002060 Object* obj;
2061 { MaybeObject* maybe_obj =
2062 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2063 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2064 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002065 return args[0]; // return TOS
2066}
2067
2068
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002069RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2070 NoHandleAllocation ha;
2071 RUNTIME_ASSERT(args.length() == 1);
2072 CONVERT_CHECKED(JSFunction, function, args[0]);
2073
2074 MaybeObject* maybe_name =
2075 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2076 String* name;
2077 if (!maybe_name->To(&name)) return maybe_name;
2078
2079 if (function->HasFastProperties()) {
2080 // Construct a new field descriptor with updated attributes.
2081 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2082 int index = instance_desc->Search(name);
2083 ASSERT(index != DescriptorArray::kNotFound);
2084 PropertyDetails details(instance_desc->GetDetails(index));
2085 CallbacksDescriptor new_desc(name,
2086 instance_desc->GetValue(index),
2087 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2088 details.index());
2089 // Construct a new field descriptors array containing the new descriptor.
2090 Object* descriptors_unchecked;
2091 { MaybeObject* maybe_descriptors_unchecked =
2092 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2093 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2094 return maybe_descriptors_unchecked;
2095 }
2096 }
2097 DescriptorArray* new_descriptors =
2098 DescriptorArray::cast(descriptors_unchecked);
2099 // Create a new map featuring the new field descriptors array.
2100 Object* map_unchecked;
2101 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2102 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2103 return maybe_map_unchecked;
2104 }
2105 }
2106 Map* new_map = Map::cast(map_unchecked);
2107 new_map->set_instance_descriptors(new_descriptors);
2108 function->set_map(new_map);
2109 } else { // Dictionary properties.
2110 // Directly manipulate the property details.
2111 int entry = function->property_dictionary()->FindEntry(name);
2112 ASSERT(entry != StringDictionary::kNotFound);
2113 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2114 PropertyDetails new_details(
2115 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2116 details.type(),
2117 details.index());
2118 function->property_dictionary()->DetailsAtPut(entry, new_details);
2119 }
2120 return function;
2121}
2122
2123
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002124RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002125 NoHandleAllocation ha;
2126 ASSERT(args.length() == 1);
2127
2128 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002129 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002130}
2131
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002132
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002133RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002134 NoHandleAllocation ha;
2135 ASSERT(args.length() == 1);
2136
2137 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002138 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002139}
2140
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002142RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002143 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002144 ASSERT(args.length() == 2);
2145
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002146 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002147 Handle<Object> code = args.at<Object>(1);
2148
2149 Handle<Context> context(target->context());
2150
2151 if (!code->IsNull()) {
2152 RUNTIME_ASSERT(code->IsJSFunction());
2153 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002154 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002155
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002156 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002157 return Failure::Exception();
2158 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002159 // Since we don't store the source for this we should never
2160 // optimize this.
2161 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002162 // Set the code, scope info, formal parameter count,
2163 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002164 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002165 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002166 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002167 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002168 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002169 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002170 // Set the source code of the target function to undefined.
2171 // SetCode is only used for built-in constructors like String,
2172 // Array, and Object, and some web code
2173 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002174 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002175 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002176 // Clear the optimization hints related to the compiled code as these are no
2177 // longer valid when the code is overwritten.
2178 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002179 context = Handle<Context>(fun->context());
2180
2181 // Make sure we get a fresh copy of the literal vector to avoid
2182 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002183 int number_of_literals = fun->NumberOfLiterals();
2184 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002185 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002186 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002187 // Insert the object, regexp and array functions in the literals
2188 // array prefix. These are the functions that will be used when
2189 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002190 literals->set(JSFunction::kLiteralGlobalContextIndex,
2191 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002192 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002193 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002194 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002195
2196 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2197 isolate->logger()->LogExistingFunction(
2198 shared, Handle<Code>(shared->code()));
2199 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002200 }
2201
2202 target->set_context(*context);
2203 return *target;
2204}
2205
2206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002207RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002208 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002209 ASSERT(args.length() == 2);
2210 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002211 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002212 RUNTIME_ASSERT(num >= 0);
2213 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002214 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002215}
2216
2217
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002218MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2219 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002220 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002221 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002222 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002223 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002224 }
2225 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002226 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002227}
2228
2229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002230RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002231 NoHandleAllocation ha;
2232 ASSERT(args.length() == 2);
2233
2234 CONVERT_CHECKED(String, subject, args[0]);
2235 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002236 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002237
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002238 uint32_t i = 0;
2239 if (index->IsSmi()) {
2240 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002241 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002242 i = value;
2243 } else {
2244 ASSERT(index->IsHeapNumber());
2245 double value = HeapNumber::cast(index)->value();
2246 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002247 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002248
2249 // Flatten the string. If someone wants to get a char at an index
2250 // in a cons string, it is likely that more indices will be
2251 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002252 Object* flat;
2253 { MaybeObject* maybe_flat = subject->TryFlatten();
2254 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2255 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002256 subject = String::cast(flat);
2257
2258 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002259 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002260 }
2261
2262 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002263}
2264
2265
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002266RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002267 NoHandleAllocation ha;
2268 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002269 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002270}
2271
lrn@chromium.org25156de2010-04-06 13:10:27 +00002272
2273class FixedArrayBuilder {
2274 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002275 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2276 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002277 length_(0),
2278 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002279 // Require a non-zero initial size. Ensures that doubling the size to
2280 // extend the array will work.
2281 ASSERT(initial_capacity > 0);
2282 }
2283
2284 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2285 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002286 length_(0),
2287 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002288 // Require a non-zero initial size. Ensures that doubling the size to
2289 // extend the array will work.
2290 ASSERT(backing_store->length() > 0);
2291 }
2292
2293 bool HasCapacity(int elements) {
2294 int length = array_->length();
2295 int required_length = length_ + elements;
2296 return (length >= required_length);
2297 }
2298
2299 void EnsureCapacity(int elements) {
2300 int length = array_->length();
2301 int required_length = length_ + elements;
2302 if (length < required_length) {
2303 int new_length = length;
2304 do {
2305 new_length *= 2;
2306 } while (new_length < required_length);
2307 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002308 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002309 array_->CopyTo(0, *extended_array, 0, length_);
2310 array_ = extended_array;
2311 }
2312 }
2313
2314 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002315 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002316 ASSERT(length_ < capacity());
2317 array_->set(length_, value);
2318 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002319 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002320 }
2321
2322 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002323 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002324 ASSERT(length_ < capacity());
2325 array_->set(length_, value);
2326 length_++;
2327 }
2328
2329 Handle<FixedArray> array() {
2330 return array_;
2331 }
2332
2333 int length() {
2334 return length_;
2335 }
2336
2337 int capacity() {
2338 return array_->length();
2339 }
2340
2341 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002342 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002343 result_array->set_length(Smi::FromInt(length_));
2344 return result_array;
2345 }
2346
2347 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002348 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002349 target_array->set_length(Smi::FromInt(length_));
2350 return target_array;
2351 }
2352
2353 private:
2354 Handle<FixedArray> array_;
2355 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002356 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002357};
2358
2359
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002360// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002361const int kStringBuilderConcatHelperLengthBits = 11;
2362const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002363
2364template <typename schar>
2365static inline void StringBuilderConcatHelper(String*,
2366 schar*,
2367 FixedArray*,
2368 int);
2369
lrn@chromium.org25156de2010-04-06 13:10:27 +00002370typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2371 StringBuilderSubstringLength;
2372typedef BitField<int,
2373 kStringBuilderConcatHelperLengthBits,
2374 kStringBuilderConcatHelperPositionBits>
2375 StringBuilderSubstringPosition;
2376
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002377
2378class ReplacementStringBuilder {
2379 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002380 ReplacementStringBuilder(Heap* heap,
2381 Handle<String> subject,
2382 int estimated_part_count)
2383 : heap_(heap),
2384 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002385 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002386 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002387 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002388 // Require a non-zero initial size. Ensures that doubling the size to
2389 // extend the array will work.
2390 ASSERT(estimated_part_count > 0);
2391 }
2392
lrn@chromium.org25156de2010-04-06 13:10:27 +00002393 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2394 int from,
2395 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002396 ASSERT(from >= 0);
2397 int length = to - from;
2398 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002399 if (StringBuilderSubstringLength::is_valid(length) &&
2400 StringBuilderSubstringPosition::is_valid(from)) {
2401 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2402 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002403 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002404 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002405 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002406 builder->Add(Smi::FromInt(-length));
2407 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002408 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002409 }
2410
2411
2412 void EnsureCapacity(int elements) {
2413 array_builder_.EnsureCapacity(elements);
2414 }
2415
2416
2417 void AddSubjectSlice(int from, int to) {
2418 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002419 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002420 }
2421
2422
2423 void AddString(Handle<String> string) {
2424 int length = string->length();
2425 ASSERT(length > 0);
2426 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002427 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002428 is_ascii_ = false;
2429 }
2430 IncrementCharacterCount(length);
2431 }
2432
2433
2434 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002435 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002436 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002437 }
2438
2439 Handle<String> joined_string;
2440 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002441 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002442 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002443 char* char_buffer = seq->GetChars();
2444 StringBuilderConcatHelper(*subject_,
2445 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002446 *array_builder_.array(),
2447 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002448 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002449 } else {
2450 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002451 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002452 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002453 uc16* char_buffer = seq->GetChars();
2454 StringBuilderConcatHelper(*subject_,
2455 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002456 *array_builder_.array(),
2457 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002458 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002459 }
2460 return joined_string;
2461 }
2462
2463
2464 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002465 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002466 V8::FatalProcessOutOfMemory("String.replace result too large.");
2467 }
2468 character_count_ += by;
2469 }
2470
lrn@chromium.org25156de2010-04-06 13:10:27 +00002471 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002472 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002473 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002474
lrn@chromium.org25156de2010-04-06 13:10:27 +00002475 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002476 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2477 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002478 }
2479
2480
ager@chromium.org04921a82011-06-27 13:21:41 +00002481 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2482 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002483 }
2484
2485
2486 void AddElement(Object* element) {
2487 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002488 ASSERT(array_builder_.capacity() > array_builder_.length());
2489 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002490 }
2491
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002492 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002493 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002494 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002495 int character_count_;
2496 bool is_ascii_;
2497};
2498
2499
2500class CompiledReplacement {
2501 public:
2502 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002503 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002504
2505 void Compile(Handle<String> replacement,
2506 int capture_count,
2507 int subject_length);
2508
2509 void Apply(ReplacementStringBuilder* builder,
2510 int match_from,
2511 int match_to,
2512 Handle<JSArray> last_match_info);
2513
2514 // Number of distinct parts of the replacement pattern.
2515 int parts() {
2516 return parts_.length();
2517 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002518
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002519 bool simple_hint() {
2520 return simple_hint_;
2521 }
2522
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002523 private:
2524 enum PartType {
2525 SUBJECT_PREFIX = 1,
2526 SUBJECT_SUFFIX,
2527 SUBJECT_CAPTURE,
2528 REPLACEMENT_SUBSTRING,
2529 REPLACEMENT_STRING,
2530
2531 NUMBER_OF_PART_TYPES
2532 };
2533
2534 struct ReplacementPart {
2535 static inline ReplacementPart SubjectMatch() {
2536 return ReplacementPart(SUBJECT_CAPTURE, 0);
2537 }
2538 static inline ReplacementPart SubjectCapture(int capture_index) {
2539 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2540 }
2541 static inline ReplacementPart SubjectPrefix() {
2542 return ReplacementPart(SUBJECT_PREFIX, 0);
2543 }
2544 static inline ReplacementPart SubjectSuffix(int subject_length) {
2545 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2546 }
2547 static inline ReplacementPart ReplacementString() {
2548 return ReplacementPart(REPLACEMENT_STRING, 0);
2549 }
2550 static inline ReplacementPart ReplacementSubString(int from, int to) {
2551 ASSERT(from >= 0);
2552 ASSERT(to > from);
2553 return ReplacementPart(-from, to);
2554 }
2555
2556 // If tag <= 0 then it is the negation of a start index of a substring of
2557 // the replacement pattern, otherwise it's a value from PartType.
2558 ReplacementPart(int tag, int data)
2559 : tag(tag), data(data) {
2560 // Must be non-positive or a PartType value.
2561 ASSERT(tag < NUMBER_OF_PART_TYPES);
2562 }
2563 // Either a value of PartType or a non-positive number that is
2564 // the negation of an index into the replacement string.
2565 int tag;
2566 // The data value's interpretation depends on the value of tag:
2567 // tag == SUBJECT_PREFIX ||
2568 // tag == SUBJECT_SUFFIX: data is unused.
2569 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2570 // tag == REPLACEMENT_SUBSTRING ||
2571 // tag == REPLACEMENT_STRING: data is index into array of substrings
2572 // of the replacement string.
2573 // tag <= 0: Temporary representation of the substring of the replacement
2574 // string ranging over -tag .. data.
2575 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2576 // substring objects.
2577 int data;
2578 };
2579
2580 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002581 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002582 Vector<Char> characters,
2583 int capture_count,
2584 int subject_length) {
2585 int length = characters.length();
2586 int last = 0;
2587 for (int i = 0; i < length; i++) {
2588 Char c = characters[i];
2589 if (c == '$') {
2590 int next_index = i + 1;
2591 if (next_index == length) { // No next character!
2592 break;
2593 }
2594 Char c2 = characters[next_index];
2595 switch (c2) {
2596 case '$':
2597 if (i > last) {
2598 // There is a substring before. Include the first "$".
2599 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2600 last = next_index + 1; // Continue after the second "$".
2601 } else {
2602 // Let the next substring start with the second "$".
2603 last = next_index;
2604 }
2605 i = next_index;
2606 break;
2607 case '`':
2608 if (i > last) {
2609 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2610 }
2611 parts->Add(ReplacementPart::SubjectPrefix());
2612 i = next_index;
2613 last = i + 1;
2614 break;
2615 case '\'':
2616 if (i > last) {
2617 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2618 }
2619 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2620 i = next_index;
2621 last = i + 1;
2622 break;
2623 case '&':
2624 if (i > last) {
2625 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2626 }
2627 parts->Add(ReplacementPart::SubjectMatch());
2628 i = next_index;
2629 last = i + 1;
2630 break;
2631 case '0':
2632 case '1':
2633 case '2':
2634 case '3':
2635 case '4':
2636 case '5':
2637 case '6':
2638 case '7':
2639 case '8':
2640 case '9': {
2641 int capture_ref = c2 - '0';
2642 if (capture_ref > capture_count) {
2643 i = next_index;
2644 continue;
2645 }
2646 int second_digit_index = next_index + 1;
2647 if (second_digit_index < length) {
2648 // Peek ahead to see if we have two digits.
2649 Char c3 = characters[second_digit_index];
2650 if ('0' <= c3 && c3 <= '9') { // Double digits.
2651 int double_digit_ref = capture_ref * 10 + c3 - '0';
2652 if (double_digit_ref <= capture_count) {
2653 next_index = second_digit_index;
2654 capture_ref = double_digit_ref;
2655 }
2656 }
2657 }
2658 if (capture_ref > 0) {
2659 if (i > last) {
2660 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2661 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002662 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002663 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2664 last = next_index + 1;
2665 }
2666 i = next_index;
2667 break;
2668 }
2669 default:
2670 i = next_index;
2671 break;
2672 }
2673 }
2674 }
2675 if (length > last) {
2676 if (last == 0) {
2677 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002678 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002679 } else {
2680 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2681 }
2682 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002683 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002684 }
2685
2686 ZoneList<ReplacementPart> parts_;
2687 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002688 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002689};
2690
2691
2692void CompiledReplacement::Compile(Handle<String> replacement,
2693 int capture_count,
2694 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002695 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002696 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002697 String::FlatContent content = replacement->GetFlatContent();
2698 ASSERT(content.IsFlat());
2699 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002700 simple_hint_ = ParseReplacementPattern(&parts_,
2701 content.ToAsciiVector(),
2702 capture_count,
2703 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002704 } else {
2705 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002706 simple_hint_ = ParseReplacementPattern(&parts_,
2707 content.ToUC16Vector(),
2708 capture_count,
2709 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002710 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002711 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002712 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002713 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002714 int substring_index = 0;
2715 for (int i = 0, n = parts_.length(); i < n; i++) {
2716 int tag = parts_[i].tag;
2717 if (tag <= 0) { // A replacement string slice.
2718 int from = -tag;
2719 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002720 replacement_substrings_.Add(
2721 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002722 parts_[i].tag = REPLACEMENT_SUBSTRING;
2723 parts_[i].data = substring_index;
2724 substring_index++;
2725 } else if (tag == REPLACEMENT_STRING) {
2726 replacement_substrings_.Add(replacement);
2727 parts_[i].data = substring_index;
2728 substring_index++;
2729 }
2730 }
2731}
2732
2733
2734void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2735 int match_from,
2736 int match_to,
2737 Handle<JSArray> last_match_info) {
2738 for (int i = 0, n = parts_.length(); i < n; i++) {
2739 ReplacementPart part = parts_[i];
2740 switch (part.tag) {
2741 case SUBJECT_PREFIX:
2742 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2743 break;
2744 case SUBJECT_SUFFIX: {
2745 int subject_length = part.data;
2746 if (match_to < subject_length) {
2747 builder->AddSubjectSlice(match_to, subject_length);
2748 }
2749 break;
2750 }
2751 case SUBJECT_CAPTURE: {
2752 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002753 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002754 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2755 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2756 if (from >= 0 && to > from) {
2757 builder->AddSubjectSlice(from, to);
2758 }
2759 break;
2760 }
2761 case REPLACEMENT_SUBSTRING:
2762 case REPLACEMENT_STRING:
2763 builder->AddString(replacement_substrings_[part.data]);
2764 break;
2765 default:
2766 UNREACHABLE();
2767 }
2768 }
2769}
2770
2771
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002772void FindAsciiStringIndices(Vector<const char> subject,
2773 char pattern,
2774 ZoneList<int>* indices,
2775 unsigned int limit) {
2776 ASSERT(limit > 0);
2777 // Collect indices of pattern in subject using memchr.
2778 // Stop after finding at most limit values.
2779 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2780 const char* subject_end = subject_start + subject.length();
2781 const char* pos = subject_start;
2782 while (limit > 0) {
2783 pos = reinterpret_cast<const char*>(
2784 memchr(pos, pattern, subject_end - pos));
2785 if (pos == NULL) return;
2786 indices->Add(static_cast<int>(pos - subject_start));
2787 pos++;
2788 limit--;
2789 }
2790}
2791
2792
2793template <typename SubjectChar, typename PatternChar>
2794void FindStringIndices(Isolate* isolate,
2795 Vector<const SubjectChar> subject,
2796 Vector<const PatternChar> pattern,
2797 ZoneList<int>* indices,
2798 unsigned int limit) {
2799 ASSERT(limit > 0);
2800 // Collect indices of pattern in subject.
2801 // Stop after finding at most limit values.
2802 int pattern_length = pattern.length();
2803 int index = 0;
2804 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2805 while (limit > 0) {
2806 index = search.Search(subject, index);
2807 if (index < 0) return;
2808 indices->Add(index);
2809 index += pattern_length;
2810 limit--;
2811 }
2812}
2813
2814
2815void FindStringIndicesDispatch(Isolate* isolate,
2816 String* subject,
2817 String* pattern,
2818 ZoneList<int>* indices,
2819 unsigned int limit) {
2820 {
2821 AssertNoAllocation no_gc;
2822 String::FlatContent subject_content = subject->GetFlatContent();
2823 String::FlatContent pattern_content = pattern->GetFlatContent();
2824 ASSERT(subject_content.IsFlat());
2825 ASSERT(pattern_content.IsFlat());
2826 if (subject_content.IsAscii()) {
2827 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2828 if (pattern_content.IsAscii()) {
2829 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2830 if (pattern_vector.length() == 1) {
2831 FindAsciiStringIndices(subject_vector,
2832 pattern_vector[0],
2833 indices,
2834 limit);
2835 } else {
2836 FindStringIndices(isolate,
2837 subject_vector,
2838 pattern_vector,
2839 indices,
2840 limit);
2841 }
2842 } else {
2843 FindStringIndices(isolate,
2844 subject_vector,
2845 pattern_content.ToUC16Vector(),
2846 indices,
2847 limit);
2848 }
2849 } else {
2850 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002851 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002852 FindStringIndices(isolate,
2853 subject_vector,
2854 pattern_content.ToAsciiVector(),
2855 indices,
2856 limit);
2857 } else {
2858 FindStringIndices(isolate,
2859 subject_vector,
2860 pattern_content.ToUC16Vector(),
2861 indices,
2862 limit);
2863 }
2864 }
2865 }
2866}
2867
2868
2869template<typename ResultSeqString>
2870MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2871 Isolate* isolate,
2872 Handle<String> subject,
2873 Handle<JSRegExp> pattern_regexp,
2874 Handle<String> replacement) {
2875 ASSERT(subject->IsFlat());
2876 ASSERT(replacement->IsFlat());
2877
2878 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2879 ZoneList<int> indices(8);
2880 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2881 String* pattern =
2882 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2883 int subject_len = subject->length();
2884 int pattern_len = pattern->length();
2885 int replacement_len = replacement->length();
2886
2887 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2888
2889 int matches = indices.length();
2890 if (matches == 0) return *subject;
2891
2892 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2893 int subject_pos = 0;
2894 int result_pos = 0;
2895
2896 Handle<ResultSeqString> result;
2897 if (ResultSeqString::kHasAsciiEncoding) {
2898 result = Handle<ResultSeqString>::cast(
2899 isolate->factory()->NewRawAsciiString(result_len));
2900 } else {
2901 result = Handle<ResultSeqString>::cast(
2902 isolate->factory()->NewRawTwoByteString(result_len));
2903 }
2904
2905 for (int i = 0; i < matches; i++) {
2906 // Copy non-matched subject content.
2907 if (subject_pos < indices.at(i)) {
2908 String::WriteToFlat(*subject,
2909 result->GetChars() + result_pos,
2910 subject_pos,
2911 indices.at(i));
2912 result_pos += indices.at(i) - subject_pos;
2913 }
2914
2915 // Replace match.
2916 if (replacement_len > 0) {
2917 String::WriteToFlat(*replacement,
2918 result->GetChars() + result_pos,
2919 0,
2920 replacement_len);
2921 result_pos += replacement_len;
2922 }
2923
2924 subject_pos = indices.at(i) + pattern_len;
2925 }
2926 // Add remaining subject content at the end.
2927 if (subject_pos < subject_len) {
2928 String::WriteToFlat(*subject,
2929 result->GetChars() + result_pos,
2930 subject_pos,
2931 subject_len);
2932 }
2933 return *result;
2934}
2935
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002936
lrn@chromium.org303ada72010-10-27 09:33:13 +00002937MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002938 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002939 String* subject,
2940 JSRegExp* regexp,
2941 String* replacement,
2942 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002943 ASSERT(subject->IsFlat());
2944 ASSERT(replacement->IsFlat());
2945
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002946 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002947
2948 int length = subject->length();
2949 Handle<String> subject_handle(subject);
2950 Handle<JSRegExp> regexp_handle(regexp);
2951 Handle<String> replacement_handle(replacement);
2952 Handle<JSArray> last_match_info_handle(last_match_info);
2953 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2954 subject_handle,
2955 0,
2956 last_match_info_handle);
2957 if (match.is_null()) {
2958 return Failure::Exception();
2959 }
2960 if (match->IsNull()) {
2961 return *subject_handle;
2962 }
2963
2964 int capture_count = regexp_handle->CaptureCount();
2965
2966 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002967 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002968 CompiledReplacement compiled_replacement;
2969 compiled_replacement.Compile(replacement_handle,
2970 capture_count,
2971 length);
2972
2973 bool is_global = regexp_handle->GetFlags().is_global();
2974
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002975 // Shortcut for simple non-regexp global replacements
2976 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002977 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002978 compiled_replacement.simple_hint()) {
2979 if (subject_handle->HasOnlyAsciiChars() &&
2980 replacement_handle->HasOnlyAsciiChars()) {
2981 return StringReplaceStringWithString<SeqAsciiString>(
2982 isolate, subject_handle, regexp_handle, replacement_handle);
2983 } else {
2984 return StringReplaceStringWithString<SeqTwoByteString>(
2985 isolate, subject_handle, regexp_handle, replacement_handle);
2986 }
2987 }
2988
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002989 // Guessing the number of parts that the final result string is built
2990 // from. Global regexps can match any number of times, so we guess
2991 // conservatively.
2992 int expected_parts =
2993 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002994 ReplacementStringBuilder builder(isolate->heap(),
2995 subject_handle,
2996 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002997
2998 // Index of end of last match.
2999 int prev = 0;
3000
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003001 // Number of parts added by compiled replacement plus preceeding
3002 // string and possibly suffix after last match. It is possible for
3003 // all components to use two elements when encoded as two smis.
3004 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003005 bool matched = true;
3006 do {
3007 ASSERT(last_match_info_handle->HasFastElements());
3008 // Increase the capacity of the builder before entering local handle-scope,
3009 // so its internal buffer can safely allocate a new handle if it grows.
3010 builder.EnsureCapacity(parts_added_per_loop);
3011
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003012 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003013 int start, end;
3014 {
3015 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003016 FixedArray* match_info_array =
3017 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003018
3019 ASSERT_EQ(capture_count * 2 + 2,
3020 RegExpImpl::GetLastCaptureCount(match_info_array));
3021 start = RegExpImpl::GetCapture(match_info_array, 0);
3022 end = RegExpImpl::GetCapture(match_info_array, 1);
3023 }
3024
3025 if (prev < start) {
3026 builder.AddSubjectSlice(prev, start);
3027 }
3028 compiled_replacement.Apply(&builder,
3029 start,
3030 end,
3031 last_match_info_handle);
3032 prev = end;
3033
3034 // Only continue checking for global regexps.
3035 if (!is_global) break;
3036
3037 // Continue from where the match ended, unless it was an empty match.
3038 int next = end;
3039 if (start == end) {
3040 next = end + 1;
3041 if (next > length) break;
3042 }
3043
3044 match = RegExpImpl::Exec(regexp_handle,
3045 subject_handle,
3046 next,
3047 last_match_info_handle);
3048 if (match.is_null()) {
3049 return Failure::Exception();
3050 }
3051 matched = !match->IsNull();
3052 } while (matched);
3053
3054 if (prev < length) {
3055 builder.AddSubjectSlice(prev, length);
3056 }
3057
3058 return *(builder.ToString());
3059}
3060
3061
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003062template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003063MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003064 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003065 String* subject,
3066 JSRegExp* regexp,
3067 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003068 ASSERT(subject->IsFlat());
3069
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003070 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003071
3072 Handle<String> subject_handle(subject);
3073 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003074
3075 // Shortcut for simple non-regexp global replacements
3076 if (regexp_handle->GetFlags().is_global() &&
3077 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3078 Handle<String> empty_string_handle(HEAP->empty_string());
3079 if (subject_handle->HasOnlyAsciiChars()) {
3080 return StringReplaceStringWithString<SeqAsciiString>(
3081 isolate, subject_handle, regexp_handle, empty_string_handle);
3082 } else {
3083 return StringReplaceStringWithString<SeqTwoByteString>(
3084 isolate, subject_handle, regexp_handle, empty_string_handle);
3085 }
3086 }
3087
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003088 Handle<JSArray> last_match_info_handle(last_match_info);
3089 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3090 subject_handle,
3091 0,
3092 last_match_info_handle);
3093 if (match.is_null()) return Failure::Exception();
3094 if (match->IsNull()) return *subject_handle;
3095
3096 ASSERT(last_match_info_handle->HasFastElements());
3097
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003098 int start, end;
3099 {
3100 AssertNoAllocation match_info_array_is_not_in_a_handle;
3101 FixedArray* match_info_array =
3102 FixedArray::cast(last_match_info_handle->elements());
3103
3104 start = RegExpImpl::GetCapture(match_info_array, 0);
3105 end = RegExpImpl::GetCapture(match_info_array, 1);
3106 }
3107
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003108 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003109 int new_length = length - (end - start);
3110 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003111 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003112 }
3113 Handle<ResultSeqString> answer;
3114 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003115 answer = Handle<ResultSeqString>::cast(
3116 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003117 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003118 answer = Handle<ResultSeqString>::cast(
3119 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003120 }
3121
3122 // If the regexp isn't global, only match once.
3123 if (!regexp_handle->GetFlags().is_global()) {
3124 if (start > 0) {
3125 String::WriteToFlat(*subject_handle,
3126 answer->GetChars(),
3127 0,
3128 start);
3129 }
3130 if (end < length) {
3131 String::WriteToFlat(*subject_handle,
3132 answer->GetChars() + start,
3133 end,
3134 length);
3135 }
3136 return *answer;
3137 }
3138
3139 int prev = 0; // Index of end of last match.
3140 int next = 0; // Start of next search (prev unless last match was empty).
3141 int position = 0;
3142
3143 do {
3144 if (prev < start) {
3145 // Add substring subject[prev;start] to answer string.
3146 String::WriteToFlat(*subject_handle,
3147 answer->GetChars() + position,
3148 prev,
3149 start);
3150 position += start - prev;
3151 }
3152 prev = end;
3153 next = end;
3154 // Continue from where the match ended, unless it was an empty match.
3155 if (start == end) {
3156 next++;
3157 if (next > length) break;
3158 }
3159 match = RegExpImpl::Exec(regexp_handle,
3160 subject_handle,
3161 next,
3162 last_match_info_handle);
3163 if (match.is_null()) return Failure::Exception();
3164 if (match->IsNull()) break;
3165
3166 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003167 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003168 {
3169 AssertNoAllocation match_info_array_is_not_in_a_handle;
3170 FixedArray* match_info_array =
3171 FixedArray::cast(last_match_info_handle->elements());
3172 start = RegExpImpl::GetCapture(match_info_array, 0);
3173 end = RegExpImpl::GetCapture(match_info_array, 1);
3174 }
3175 } while (true);
3176
3177 if (prev < length) {
3178 // Add substring subject[prev;length] to answer string.
3179 String::WriteToFlat(*subject_handle,
3180 answer->GetChars() + position,
3181 prev,
3182 length);
3183 position += length - prev;
3184 }
3185
3186 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003187 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003188 }
3189
3190 // Shorten string and fill
3191 int string_size = ResultSeqString::SizeFor(position);
3192 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3193 int delta = allocated_string_size - string_size;
3194
3195 answer->set_length(position);
3196 if (delta == 0) return *answer;
3197
3198 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003199 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003200 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3201 MemoryChunk::IncrementLiveBytes(answer->address(), -delta);
3202 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003203
3204 return *answer;
3205}
3206
3207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003208RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003209 ASSERT(args.length() == 4);
3210
3211 CONVERT_CHECKED(String, subject, args[0]);
3212 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003213 Object* flat_subject;
3214 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3215 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3216 return maybe_flat_subject;
3217 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003218 }
3219 subject = String::cast(flat_subject);
3220 }
3221
3222 CONVERT_CHECKED(String, replacement, args[2]);
3223 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003224 Object* flat_replacement;
3225 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3226 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3227 return maybe_flat_replacement;
3228 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003229 }
3230 replacement = String::cast(flat_replacement);
3231 }
3232
3233 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3234 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3235
3236 ASSERT(last_match_info->HasFastElements());
3237
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003238 if (replacement->length() == 0) {
3239 if (subject->HasOnlyAsciiChars()) {
3240 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003241 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003242 } else {
3243 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003244 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003245 }
3246 }
3247
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003248 return StringReplaceRegExpWithString(isolate,
3249 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003250 regexp,
3251 replacement,
3252 last_match_info);
3253}
3254
3255
ager@chromium.org7c537e22008-10-16 08:43:32 +00003256// Perform string match of pattern on subject, starting at start index.
3257// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003258// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003259int Runtime::StringMatch(Isolate* isolate,
3260 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003261 Handle<String> pat,
3262 int start_index) {
3263 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003264 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003265
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003266 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003267 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003268
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003269 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003270 if (start_index + pattern_length > subject_length) return -1;
3271
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003272 if (!sub->IsFlat()) FlattenString(sub);
3273 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003274
ager@chromium.org7c537e22008-10-16 08:43:32 +00003275 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003276 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003277 String::FlatContent seq_sub = sub->GetFlatContent();
3278 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003279
ager@chromium.org7c537e22008-10-16 08:43:32 +00003280 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003281 if (seq_pat.IsAscii()) {
3282 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3283 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003284 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003285 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003286 pat_vector,
3287 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003288 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003289 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003290 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003291 pat_vector,
3292 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003293 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003294 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3295 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003296 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003297 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003298 pat_vector,
3299 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003300 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003301 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003302 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003303 pat_vector,
3304 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003305}
3306
3307
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003308RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003309 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003310 ASSERT(args.length() == 3);
3311
ager@chromium.org7c537e22008-10-16 08:43:32 +00003312 CONVERT_ARG_CHECKED(String, sub, 0);
3313 CONVERT_ARG_CHECKED(String, pat, 1);
3314
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003315 Object* index = args[2];
3316 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003317 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003318
ager@chromium.org870a0b62008-11-04 11:43:05 +00003319 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003320 int position =
3321 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003322 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003323}
3324
3325
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003326template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003327static int StringMatchBackwards(Vector<const schar> subject,
3328 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003329 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003330 int pattern_length = pattern.length();
3331 ASSERT(pattern_length >= 1);
3332 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003333
3334 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003335 for (int i = 0; i < pattern_length; i++) {
3336 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003337 if (c > String::kMaxAsciiCharCode) {
3338 return -1;
3339 }
3340 }
3341 }
3342
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003343 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003344 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003345 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003346 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003347 while (j < pattern_length) {
3348 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003349 break;
3350 }
3351 j++;
3352 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003353 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003354 return i;
3355 }
3356 }
3357 return -1;
3358}
3359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003360RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003361 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003362 ASSERT(args.length() == 3);
3363
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003364 CONVERT_ARG_CHECKED(String, sub, 0);
3365 CONVERT_ARG_CHECKED(String, pat, 1);
3366
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003367 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003368 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003369 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003370
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003371 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003372 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003373
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003374 if (start_index + pat_length > sub_length) {
3375 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003376 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003377
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003378 if (pat_length == 0) {
3379 return Smi::FromInt(start_index);
3380 }
3381
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003382 if (!sub->IsFlat()) FlattenString(sub);
3383 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003384
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003385 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003386 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3387
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003388 String::FlatContent sub_content = sub->GetFlatContent();
3389 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003390
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003391 if (pat_content.IsAscii()) {
3392 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3393 if (sub_content.IsAscii()) {
3394 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003395 pat_vector,
3396 start_index);
3397 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003398 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003399 pat_vector,
3400 start_index);
3401 }
3402 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003403 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3404 if (sub_content.IsAscii()) {
3405 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003406 pat_vector,
3407 start_index);
3408 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003409 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003410 pat_vector,
3411 start_index);
3412 }
3413 }
3414
3415 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003416}
3417
3418
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003419RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003420 NoHandleAllocation ha;
3421 ASSERT(args.length() == 2);
3422
3423 CONVERT_CHECKED(String, str1, args[0]);
3424 CONVERT_CHECKED(String, str2, args[1]);
3425
3426 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003427 int str1_length = str1->length();
3428 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003429
3430 // Decide trivial cases without flattening.
3431 if (str1_length == 0) {
3432 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3433 return Smi::FromInt(-str2_length);
3434 } else {
3435 if (str2_length == 0) return Smi::FromInt(str1_length);
3436 }
3437
3438 int end = str1_length < str2_length ? str1_length : str2_length;
3439
3440 // No need to flatten if we are going to find the answer on the first
3441 // character. At this point we know there is at least one character
3442 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003443 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003444 if (d != 0) return Smi::FromInt(d);
3445
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003446 str1->TryFlatten();
3447 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003448
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003449 StringInputBuffer& buf1 =
3450 *isolate->runtime_state()->string_locale_compare_buf1();
3451 StringInputBuffer& buf2 =
3452 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003453
3454 buf1.Reset(str1);
3455 buf2.Reset(str2);
3456
3457 for (int i = 0; i < end; i++) {
3458 uint16_t char1 = buf1.GetNext();
3459 uint16_t char2 = buf2.GetNext();
3460 if (char1 != char2) return Smi::FromInt(char1 - char2);
3461 }
3462
3463 return Smi::FromInt(str1_length - str2_length);
3464}
3465
3466
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003467RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003468 NoHandleAllocation ha;
3469 ASSERT(args.length() == 3);
3470
3471 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003472 int start, end;
3473 // We have a fast integer-only case here to avoid a conversion to double in
3474 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003475 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3476 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3477 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3478 start = from_number;
3479 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003480 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003481 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3482 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003483 start = FastD2I(from_number);
3484 end = FastD2I(to_number);
3485 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003486 RUNTIME_ASSERT(end >= start);
3487 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003488 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003489 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003490 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003491}
3492
3493
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003494RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003495 ASSERT_EQ(3, args.length());
3496
3497 CONVERT_ARG_CHECKED(String, subject, 0);
3498 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3499 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3500 HandleScope handles;
3501
3502 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3503
3504 if (match.is_null()) {
3505 return Failure::Exception();
3506 }
3507 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003508 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003509 }
3510 int length = subject->length();
3511
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003512 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003513 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003514 int start;
3515 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003516 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003517 {
3518 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003519 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003520 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3521 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3522 }
3523 offsets.Add(start);
3524 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003525 if (start == end) if (++end > length) break;
3526 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003527 if (match.is_null()) {
3528 return Failure::Exception();
3529 }
3530 } while (!match->IsNull());
3531 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003532 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003533 Handle<String> substring = isolate->factory()->
3534 NewSubString(subject, offsets.at(0), offsets.at(1));
3535 elements->set(0, *substring);
3536 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003537 int from = offsets.at(i * 2);
3538 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003539 Handle<String> substring = isolate->factory()->
3540 NewProperSubString(subject, from, to);
3541 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003542 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003543 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003544 result->set_length(Smi::FromInt(matches));
3545 return *result;
3546}
3547
3548
lrn@chromium.org25156de2010-04-06 13:10:27 +00003549// Two smis before and after the match, for very long strings.
3550const int kMaxBuilderEntriesPerRegExpMatch = 5;
3551
3552
3553static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3554 Handle<JSArray> last_match_info,
3555 int match_start,
3556 int match_end) {
3557 // Fill last_match_info with a single capture.
3558 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3559 AssertNoAllocation no_gc;
3560 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3561 RegExpImpl::SetLastCaptureCount(elements, 2);
3562 RegExpImpl::SetLastInput(elements, *subject);
3563 RegExpImpl::SetLastSubject(elements, *subject);
3564 RegExpImpl::SetCapture(elements, 0, match_start);
3565 RegExpImpl::SetCapture(elements, 1, match_end);
3566}
3567
3568
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003569template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003570static bool SearchStringMultiple(Isolate* isolate,
3571 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003572 Vector<const PatternChar> pattern,
3573 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003574 FixedArrayBuilder* builder,
3575 int* match_pos) {
3576 int pos = *match_pos;
3577 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003578 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003579 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003580 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003581 while (pos <= max_search_start) {
3582 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3583 *match_pos = pos;
3584 return false;
3585 }
3586 // Position of end of previous match.
3587 int match_end = pos + pattern_length;
3588 int new_pos = search.Search(subject, match_end);
3589 if (new_pos >= 0) {
3590 // A match.
3591 if (new_pos > match_end) {
3592 ReplacementStringBuilder::AddSubjectSlice(builder,
3593 match_end,
3594 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003595 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003596 pos = new_pos;
3597 builder->Add(pattern_string);
3598 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003599 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003600 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003601 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003602
lrn@chromium.org25156de2010-04-06 13:10:27 +00003603 if (pos < max_search_start) {
3604 ReplacementStringBuilder::AddSubjectSlice(builder,
3605 pos + pattern_length,
3606 subject_length);
3607 }
3608 *match_pos = pos;
3609 return true;
3610}
3611
3612
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003613static bool SearchStringMultiple(Isolate* isolate,
3614 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003615 Handle<String> pattern,
3616 Handle<JSArray> last_match_info,
3617 FixedArrayBuilder* builder) {
3618 ASSERT(subject->IsFlat());
3619 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003620
3621 // Treating as if a previous match was before first character.
3622 int match_pos = -pattern->length();
3623
3624 for (;;) { // Break when search complete.
3625 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3626 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003627 String::FlatContent subject_content = subject->GetFlatContent();
3628 String::FlatContent pattern_content = pattern->GetFlatContent();
3629 if (subject_content.IsAscii()) {
3630 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3631 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003632 if (SearchStringMultiple(isolate,
3633 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003634 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003635 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003636 builder,
3637 &match_pos)) break;
3638 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003639 if (SearchStringMultiple(isolate,
3640 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003641 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003642 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003643 builder,
3644 &match_pos)) break;
3645 }
3646 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003647 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3648 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003649 if (SearchStringMultiple(isolate,
3650 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003651 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003652 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003653 builder,
3654 &match_pos)) break;
3655 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003656 if (SearchStringMultiple(isolate,
3657 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003658 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003659 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003660 builder,
3661 &match_pos)) break;
3662 }
3663 }
3664 }
3665
3666 if (match_pos >= 0) {
3667 SetLastMatchInfoNoCaptures(subject,
3668 last_match_info,
3669 match_pos,
3670 match_pos + pattern->length());
3671 return true;
3672 }
3673 return false; // No matches at all.
3674}
3675
3676
3677static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003678 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003679 Handle<String> subject,
3680 Handle<JSRegExp> regexp,
3681 Handle<JSArray> last_match_array,
3682 FixedArrayBuilder* builder) {
3683 ASSERT(subject->IsFlat());
3684 int match_start = -1;
3685 int match_end = 0;
3686 int pos = 0;
3687 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3688 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3689
3690 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003691 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003692 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003693 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003694
3695 for (;;) { // Break on failure, return on exception.
3696 RegExpImpl::IrregexpResult result =
3697 RegExpImpl::IrregexpExecOnce(regexp,
3698 subject,
3699 pos,
3700 register_vector);
3701 if (result == RegExpImpl::RE_SUCCESS) {
3702 match_start = register_vector[0];
3703 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3704 if (match_end < match_start) {
3705 ReplacementStringBuilder::AddSubjectSlice(builder,
3706 match_end,
3707 match_start);
3708 }
3709 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003710 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003711 if (!first) {
3712 builder->Add(*isolate->factory()->NewProperSubString(subject,
3713 match_start,
3714 match_end));
3715 } else {
3716 builder->Add(*isolate->factory()->NewSubString(subject,
3717 match_start,
3718 match_end));
3719 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003720 if (match_start != match_end) {
3721 pos = match_end;
3722 } else {
3723 pos = match_end + 1;
3724 if (pos > subject_length) break;
3725 }
3726 } else if (result == RegExpImpl::RE_FAILURE) {
3727 break;
3728 } else {
3729 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3730 return result;
3731 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003732 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003733 }
3734
3735 if (match_start >= 0) {
3736 if (match_end < subject_length) {
3737 ReplacementStringBuilder::AddSubjectSlice(builder,
3738 match_end,
3739 subject_length);
3740 }
3741 SetLastMatchInfoNoCaptures(subject,
3742 last_match_array,
3743 match_start,
3744 match_end);
3745 return RegExpImpl::RE_SUCCESS;
3746 } else {
3747 return RegExpImpl::RE_FAILURE; // No matches at all.
3748 }
3749}
3750
3751
3752static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003753 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003754 Handle<String> subject,
3755 Handle<JSRegExp> regexp,
3756 Handle<JSArray> last_match_array,
3757 FixedArrayBuilder* builder) {
3758
3759 ASSERT(subject->IsFlat());
3760 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3761 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3762
3763 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003764 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003765
3766 RegExpImpl::IrregexpResult result =
3767 RegExpImpl::IrregexpExecOnce(regexp,
3768 subject,
3769 0,
3770 register_vector);
3771
3772 int capture_count = regexp->CaptureCount();
3773 int subject_length = subject->length();
3774
3775 // Position to search from.
3776 int pos = 0;
3777 // End of previous match. Differs from pos if match was empty.
3778 int match_end = 0;
3779 if (result == RegExpImpl::RE_SUCCESS) {
3780 // Need to keep a copy of the previous match for creating last_match_info
3781 // at the end, so we have two vectors that we swap between.
3782 OffsetsVector registers2(required_registers);
3783 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003784 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003785 do {
3786 int match_start = register_vector[0];
3787 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3788 if (match_end < match_start) {
3789 ReplacementStringBuilder::AddSubjectSlice(builder,
3790 match_end,
3791 match_start);
3792 }
3793 match_end = register_vector[1];
3794
3795 {
3796 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003797 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003798 // Arguments array to replace function is match, captures, index and
3799 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003800 Handle<FixedArray> elements =
3801 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003802 Handle<String> match;
3803 if (!first) {
3804 match = isolate->factory()->NewProperSubString(subject,
3805 match_start,
3806 match_end);
3807 } else {
3808 match = isolate->factory()->NewSubString(subject,
3809 match_start,
3810 match_end);
3811 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003812 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003813 for (int i = 1; i <= capture_count; i++) {
3814 int start = register_vector[i * 2];
3815 if (start >= 0) {
3816 int end = register_vector[i * 2 + 1];
3817 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003818 Handle<String> substring;
3819 if (!first) {
3820 substring = isolate->factory()->NewProperSubString(subject,
3821 start,
3822 end);
3823 } else {
3824 substring = isolate->factory()->NewSubString(subject, start, end);
3825 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003826 elements->set(i, *substring);
3827 } else {
3828 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003829 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003830 }
3831 }
3832 elements->set(capture_count + 1, Smi::FromInt(match_start));
3833 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003834 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003835 }
3836 // Swap register vectors, so the last successful match is in
3837 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003838 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003839 prev_register_vector = register_vector;
3840 register_vector = tmp;
3841
3842 if (match_end > match_start) {
3843 pos = match_end;
3844 } else {
3845 pos = match_end + 1;
3846 if (pos > subject_length) {
3847 break;
3848 }
3849 }
3850
3851 result = RegExpImpl::IrregexpExecOnce(regexp,
3852 subject,
3853 pos,
3854 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003855 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003856 } while (result == RegExpImpl::RE_SUCCESS);
3857
3858 if (result != RegExpImpl::RE_EXCEPTION) {
3859 // Finished matching, with at least one match.
3860 if (match_end < subject_length) {
3861 ReplacementStringBuilder::AddSubjectSlice(builder,
3862 match_end,
3863 subject_length);
3864 }
3865
3866 int last_match_capture_count = (capture_count + 1) * 2;
3867 int last_match_array_size =
3868 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3869 last_match_array->EnsureSize(last_match_array_size);
3870 AssertNoAllocation no_gc;
3871 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3872 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3873 RegExpImpl::SetLastSubject(elements, *subject);
3874 RegExpImpl::SetLastInput(elements, *subject);
3875 for (int i = 0; i < last_match_capture_count; i++) {
3876 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3877 }
3878 return RegExpImpl::RE_SUCCESS;
3879 }
3880 }
3881 // No matches at all, return failure or exception result directly.
3882 return result;
3883}
3884
3885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003886RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003887 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003888 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003889
3890 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003891 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003892 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3893 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3894 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3895
3896 ASSERT(last_match_info->HasFastElements());
3897 ASSERT(regexp->GetFlags().is_global());
3898 Handle<FixedArray> result_elements;
3899 if (result_array->HasFastElements()) {
3900 result_elements =
3901 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003902 }
3903 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003904 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003905 }
3906 FixedArrayBuilder builder(result_elements);
3907
3908 if (regexp->TypeTag() == JSRegExp::ATOM) {
3909 Handle<String> pattern(
3910 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003911 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003912 if (SearchStringMultiple(isolate, subject, pattern,
3913 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003914 return *builder.ToJSArray(result_array);
3915 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003916 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003917 }
3918
3919 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3920
3921 RegExpImpl::IrregexpResult result;
3922 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003923 result = SearchRegExpNoCaptureMultiple(isolate,
3924 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003925 regexp,
3926 last_match_info,
3927 &builder);
3928 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003929 result = SearchRegExpMultiple(isolate,
3930 subject,
3931 regexp,
3932 last_match_info,
3933 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003934 }
3935 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003936 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003937 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3938 return Failure::Exception();
3939}
3940
3941
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003942RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003943 NoHandleAllocation ha;
3944 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003945 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003946 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003947
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003948 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003949 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003950 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003951 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003952 // Character array used for conversion.
3953 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003954 return isolate->heap()->
3955 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003956 }
3957 }
3958
3959 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003960 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003961 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003962 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003963 }
3964 if (isinf(value)) {
3965 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003966 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003967 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003968 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003969 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003970 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003971 MaybeObject* result =
3972 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003973 DeleteArray(str);
3974 return result;
3975}
3976
3977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003978RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003979 NoHandleAllocation ha;
3980 ASSERT(args.length() == 2);
3981
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003982 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003983 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003984 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985 }
3986 if (isinf(value)) {
3987 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003988 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003989 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003990 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003991 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003992 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003993 int f = FastD2I(f_number);
3994 RUNTIME_ASSERT(f >= 0);
3995 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003996 MaybeObject* res =
3997 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003999 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004000}
4001
4002
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004003RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004004 NoHandleAllocation ha;
4005 ASSERT(args.length() == 2);
4006
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004007 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004008 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004009 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010 }
4011 if (isinf(value)) {
4012 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004013 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004015 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004016 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004017 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004018 int f = FastD2I(f_number);
4019 RUNTIME_ASSERT(f >= -1 && f <= 20);
4020 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004021 MaybeObject* res =
4022 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004023 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004024 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004025}
4026
4027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004028RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029 NoHandleAllocation ha;
4030 ASSERT(args.length() == 2);
4031
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004032 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004034 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004035 }
4036 if (isinf(value)) {
4037 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004038 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004039 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004040 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004041 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004042 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004043 int f = FastD2I(f_number);
4044 RUNTIME_ASSERT(f >= 1 && f <= 21);
4045 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004046 MaybeObject* res =
4047 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004048 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004049 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004050}
4051
4052
4053// Returns a single character string where first character equals
4054// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004055static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004056 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004057 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004058 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004059 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004060 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004061 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004062}
4063
4064
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004065MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4066 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004067 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004068 // Handle [] indexing on Strings
4069 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004070 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4071 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 }
4073
4074 // Handle [] indexing on String objects
4075 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004076 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4077 Handle<Object> result =
4078 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4079 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004080 }
4081
4082 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004083 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084 return prototype->GetElement(index);
4085 }
4086
4087 return object->GetElement(index);
4088}
4089
4090
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004091MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4092 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004093 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004094 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004095
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004096 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004097 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004099 isolate->factory()->NewTypeError("non_object_property_load",
4100 HandleVector(args, 2));
4101 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102 }
4103
4104 // Check if the given key is an array index.
4105 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004106 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004107 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004108 }
4109
4110 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004111 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004113 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004114 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004115 bool has_pending_exception = false;
4116 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004117 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004119 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004120 }
4121
ager@chromium.org32912102009-01-16 10:38:43 +00004122 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004123 // the element if so.
4124 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004125 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004127 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004128 }
4129}
4130
4131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004132RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004133 NoHandleAllocation ha;
4134 ASSERT(args.length() == 2);
4135
4136 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004137 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004139 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004140}
4141
4142
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004143MaybeObject* TransitionElements(Handle<Object> object,
4144 ElementsKind to_kind,
4145 Isolate* isolate) {
4146 HandleScope scope(isolate);
4147 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
4148 ElementsKind from_kind =
4149 Handle<JSObject>::cast(object)->map()->elements_kind();
4150 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
4151 Handle<Object> result =
4152 TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
4153 if (result.is_null()) return isolate->ThrowIllegalOperation();
4154 return *result;
4155 }
4156 return isolate->ThrowIllegalOperation();
4157}
4158
4159
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004160// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004161RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004162 NoHandleAllocation ha;
4163 ASSERT(args.length() == 2);
4164
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004165 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004166 // itself.
4167 //
4168 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004169 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004170 // global proxy object never has properties. This is the case
4171 // because the global proxy object forwards everything to its hidden
4172 // prototype including local lookups.
4173 //
4174 // Additionally, we need to make sure that we do not cache results
4175 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004176 if (args[0]->IsJSObject()) {
4177 if (!args[0]->IsJSGlobalProxy() &&
4178 !args[0]->IsAccessCheckNeeded() &&
4179 args[1]->IsString()) {
4180 JSObject* receiver = JSObject::cast(args[0]);
4181 String* key = String::cast(args[1]);
4182 if (receiver->HasFastProperties()) {
4183 // Attempt to use lookup cache.
4184 Map* receiver_map = receiver->map();
4185 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4186 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4187 if (offset != -1) {
4188 Object* value = receiver->FastPropertyAt(offset);
4189 return value->IsTheHole()
4190 ? isolate->heap()->undefined_value()
4191 : value;
4192 }
4193 // Lookup cache miss. Perform lookup and update the cache if
4194 // appropriate.
4195 LookupResult result(isolate);
4196 receiver->LocalLookup(key, &result);
4197 if (result.IsProperty() && result.type() == FIELD) {
4198 int offset = result.GetFieldIndex();
4199 keyed_lookup_cache->Update(receiver_map, key, offset);
4200 return receiver->FastPropertyAt(offset);
4201 }
4202 } else {
4203 // Attempt dictionary lookup.
4204 StringDictionary* dictionary = receiver->property_dictionary();
4205 int entry = dictionary->FindEntry(key);
4206 if ((entry != StringDictionary::kNotFound) &&
4207 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4208 Object* value = dictionary->ValueAt(entry);
4209 if (!receiver->IsGlobalObject()) return value;
4210 value = JSGlobalPropertyCell::cast(value)->value();
4211 if (!value->IsTheHole()) return value;
4212 // If value is the hole do the general lookup.
4213 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004214 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004215 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4216 // JSObject without a string key. If the key is a Smi, check for a
4217 // definite out-of-bounds access to elements, which is a strong indicator
4218 // that subsequent accesses will also call the runtime. Proactively
4219 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4220 // doubles for those future calls in the case that the elements would
4221 // become FAST_DOUBLE_ELEMENTS.
4222 Handle<JSObject> js_object(args.at<JSObject>(0));
4223 ElementsKind elements_kind = js_object->GetElementsKind();
4224 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4225 elements_kind == FAST_DOUBLE_ELEMENTS) {
4226 FixedArrayBase* elements = js_object->elements();
4227 if (args.at<Smi>(1)->value() >= elements->length()) {
4228 MaybeObject* maybe_object = TransitionElements(js_object,
4229 FAST_ELEMENTS,
4230 isolate);
4231 if (maybe_object->IsFailure()) return maybe_object;
4232 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004233 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004234 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004235 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4236 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004237 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004238 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004239 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004240 if (index >= 0 && index < str->length()) {
4241 Handle<Object> result = GetCharAt(str, index);
4242 return *result;
4243 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004244 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004245
4246 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004247 return Runtime::GetObjectProperty(isolate,
4248 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004249 args.at<Object>(1));
4250}
4251
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004252// Implements part of 8.12.9 DefineOwnProperty.
4253// There are 3 cases that lead here:
4254// Step 4b - define a new accessor property.
4255// Steps 9c & 12 - replace an existing data property with an accessor property.
4256// Step 12 - update an existing accessor property with an accessor or generic
4257// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004258RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004259 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004260 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004261 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4262 CONVERT_CHECKED(String, name, args[1]);
4263 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004264 Object* fun = args[3];
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004265 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004266 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4267 int unchecked = flag_attr->value();
4268 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4269 RUNTIME_ASSERT(!obj->IsNull());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004270 LookupResult result(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004271 obj->LocalLookupRealNamedProperty(name, &result);
4272
4273 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4274 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4275 // delete it to avoid running into trouble in DefineAccessor, which
4276 // handles this incorrectly if the property is readonly (does nothing)
4277 if (result.IsProperty() &&
4278 (result.type() == FIELD || result.type() == NORMAL
4279 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004280 Object* ok;
4281 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004282 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004283 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4284 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004285 }
4286 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4287}
4288
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004289// Implements part of 8.12.9 DefineOwnProperty.
4290// There are 3 cases that lead here:
4291// Step 4a - define a new data property.
4292// Steps 9b & 12 - replace an existing accessor property with a data property.
4293// Step 12 - update an existing data property with a data or generic
4294// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004295RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004296 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004297 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004298 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4299 CONVERT_ARG_CHECKED(String, name, 1);
4300 Handle<Object> obj_value = args.at<Object>(2);
4301
4302 CONVERT_CHECKED(Smi, flag, args[3]);
4303 int unchecked = flag->value();
4304 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4305
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004306 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4307
4308 // Check if this is an element.
4309 uint32_t index;
4310 bool is_element = name->AsArrayIndex(&index);
4311
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004312 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004313 // If elements are in fast case we always implicitly assume that:
4314 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004315 if (is_element && (attr != NONE ||
4316 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004317 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004318 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004319 // We do not need to do access checks here since these has already
4320 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004321 Handle<Object> proto(js_object->GetPrototype());
4322 // If proxy is detached, ignore the assignment. Alternatively,
4323 // we could throw an exception.
4324 if (proto->IsNull()) return *obj_value;
4325 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004326 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004327
4328 // Don't allow element properties to be redefined on objects with external
4329 // array elements.
4330 if (js_object->HasExternalArrayElements()) {
4331 Handle<Object> args[2] = { js_object, name };
4332 Handle<Object> error =
4333 isolate->factory()->NewTypeError("redef_external_array_element",
4334 HandleVector(args, 2));
4335 return isolate->Throw(*error);
4336 }
4337
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004338 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004339 // Make sure that we never go back to fast case.
4340 dictionary->set_requires_slow_elements();
4341 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004342 Handle<NumberDictionary> extended_dictionary =
4343 NumberDictionarySet(dictionary, index, obj_value, details);
4344 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004345 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004346 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4347 } else {
4348 js_object->set_elements(*extended_dictionary);
4349 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004350 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004351 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004352 }
4353
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004354 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004355 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004356
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004357 // To be compatible with safari we do not change the value on API objects
4358 // in defineProperty. Firefox disagrees here, and actually changes the value.
4359 if (result.IsProperty() &&
4360 (result.type() == CALLBACKS) &&
4361 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004362 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004363 }
4364
ager@chromium.org5c838252010-02-19 08:53:10 +00004365 // Take special care when attributes are different and there is already
4366 // a property. For simplicity we normalize the property which enables us
4367 // to not worry about changing the instance_descriptor and creating a new
4368 // map. The current version of SetObjectProperty does not handle attributes
4369 // correctly in the case where a property is a field and is reset with
4370 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004371 if (result.IsProperty() &&
4372 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004373 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004374 if (js_object->IsJSGlobalProxy()) {
4375 // Since the result is a property, the prototype will exist so
4376 // we don't have to check for null.
4377 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004378 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004379 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004380 // Use IgnoreAttributes version since a readonly property may be
4381 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004382 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4383 *obj_value,
4384 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004385 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004386
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004387 return Runtime::ForceSetObjectProperty(isolate,
4388 js_object,
4389 name,
4390 obj_value,
4391 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004392}
4393
4394
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004395// Special case for elements if any of the flags are true.
4396// If elements are in fast case we always implicitly assume that:
4397// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4398static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4399 Handle<JSObject> js_object,
4400 uint32_t index,
4401 Handle<Object> value,
4402 PropertyAttributes attr) {
4403 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004404 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004405 // Make sure that we never go back to fast case.
4406 dictionary->set_requires_slow_elements();
4407 PropertyDetails details = PropertyDetails(attr, NORMAL);
4408 Handle<NumberDictionary> extended_dictionary =
4409 NumberDictionarySet(dictionary, index, value, details);
4410 if (*extended_dictionary != *dictionary) {
4411 js_object->set_elements(*extended_dictionary);
4412 }
4413 return *value;
4414}
4415
4416
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004417MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4418 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004419 Handle<Object> key,
4420 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004421 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004422 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004423 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004424
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004425 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004426 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004427 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004428 isolate->factory()->NewTypeError("non_object_property_store",
4429 HandleVector(args, 2));
4430 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004431 }
4432
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004433 if (object->IsJSProxy()) {
4434 bool has_pending_exception = false;
4435 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4436 if (has_pending_exception) return Failure::Exception();
4437 return JSProxy::cast(*object)->SetProperty(
4438 String::cast(*name), *value, attr, strict_mode);
4439 }
4440
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004441 // If the object isn't a JavaScript object, we ignore the store.
4442 if (!object->IsJSObject()) return *value;
4443
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004444 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4445
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004446 // Check if the given key is an array index.
4447 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004448 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004449 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4450 // of a string using [] notation. We need to support this too in
4451 // JavaScript.
4452 // In the case of a String object we just need to redirect the assignment to
4453 // the underlying string if the index is in range. Since the underlying
4454 // string does nothing with the assignment then we can ignore such
4455 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004456 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004457 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004458 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004459
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004460 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4461 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4462 }
4463
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004464 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004465 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004466 return *value;
4467 }
4468
4469 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004470 Handle<Object> result;
4471 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004472 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4473 return NormalizeObjectSetElement(isolate,
4474 js_object,
4475 index,
4476 value,
4477 attr);
4478 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004479 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004480 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004481 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004482 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004483 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004484 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004485 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004486 return *value;
4487 }
4488
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004489 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004490 bool has_pending_exception = false;
4491 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4492 if (has_pending_exception) return Failure::Exception();
4493 Handle<String> name = Handle<String>::cast(converted);
4494
4495 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004496 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004497 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004498 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004499 }
4500}
4501
4502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004503MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4504 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004505 Handle<Object> key,
4506 Handle<Object> value,
4507 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004508 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004509
4510 // Check if the given key is an array index.
4511 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004512 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004513 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4514 // of a string using [] notation. We need to support this too in
4515 // JavaScript.
4516 // In the case of a String object we just need to redirect the assignment to
4517 // the underlying string if the index is in range. Since the underlying
4518 // string does nothing with the assignment then we can ignore such
4519 // assignments.
4520 if (js_object->IsStringObjectWithCharacterAt(index)) {
4521 return *value;
4522 }
4523
whesse@chromium.org7b260152011-06-20 15:33:18 +00004524 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004525 }
4526
4527 if (key->IsString()) {
4528 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004529 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004530 } else {
4531 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004532 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004533 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4534 *value,
4535 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004536 }
4537 }
4538
4539 // Call-back into JavaScript to convert the key to a string.
4540 bool has_pending_exception = false;
4541 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4542 if (has_pending_exception) return Failure::Exception();
4543 Handle<String> name = Handle<String>::cast(converted);
4544
4545 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004546 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004547 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004548 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004549 }
4550}
4551
4552
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004553MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004554 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004555 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004556 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004557
4558 // Check if the given key is an array index.
4559 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004560 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004561 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4562 // characters of a string using [] notation. In the case of a
4563 // String object we just need to redirect the deletion to the
4564 // underlying string if the index is in range. Since the
4565 // underlying string does nothing with the deletion, we can ignore
4566 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004567 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004568 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004569 }
4570
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004571 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004572 }
4573
4574 Handle<String> key_string;
4575 if (key->IsString()) {
4576 key_string = Handle<String>::cast(key);
4577 } else {
4578 // Call-back into JavaScript to convert the key to a string.
4579 bool has_pending_exception = false;
4580 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4581 if (has_pending_exception) return Failure::Exception();
4582 key_string = Handle<String>::cast(converted);
4583 }
4584
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004585 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004586 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004587}
4588
4589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004590RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004591 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004592 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004593
4594 Handle<Object> object = args.at<Object>(0);
4595 Handle<Object> key = args.at<Object>(1);
4596 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004597 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004598 RUNTIME_ASSERT(
4599 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004600 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004601 PropertyAttributes attributes =
4602 static_cast<PropertyAttributes>(unchecked_attributes);
4603
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004604 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004605 if (args.length() == 5) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004606 CONVERT_STRICT_MODE_ARG(strict_mode_flag, 4);
4607 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004608 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004609
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004610 return Runtime::SetObjectProperty(isolate,
4611 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004612 key,
4613 value,
4614 attributes,
4615 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004616}
4617
4618
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004619RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4620 NoHandleAllocation ha;
4621 RUNTIME_ASSERT(args.length() == 1);
4622 Handle<Object> object = args.at<Object>(0);
4623 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4624}
4625
4626
4627RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4628 NoHandleAllocation ha;
4629 RUNTIME_ASSERT(args.length() == 1);
4630 Handle<Object> object = args.at<Object>(0);
4631 return TransitionElements(object, FAST_ELEMENTS, isolate);
4632}
4633
4634
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004635// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004636// This is used to decide if we should transform null and undefined
4637// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004638RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004639 NoHandleAllocation ha;
4640 RUNTIME_ASSERT(args.length() == 1);
4641
4642 Handle<Object> object = args.at<Object>(0);
4643
4644 if (object->IsJSFunction()) {
4645 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004646 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004647 }
4648 return isolate->heap()->undefined_value();
4649}
4650
4651
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004652RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4653 RUNTIME_ASSERT(args.length() == 5);
4654 CONVERT_ARG_CHECKED(JSObject, object, 0);
4655 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4656 Handle<Object> value = args.at<Object>(2);
4657 CONVERT_ARG_CHECKED(FixedArray, literals, 3);
4658 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4659 HandleScope scope;
4660
4661 Object* raw_boilerplate_object = literals->get(literal_index);
4662 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4663#if DEBUG
4664 ElementsKind elements_kind = object->GetElementsKind();
4665#endif
4666 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4667 // Smis should never trigger transitions.
4668 ASSERT(!value->IsSmi());
4669
4670 if (value->IsNumber()) {
4671 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
4672 TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4673 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4674 FixedDoubleArray* double_array =
4675 FixedDoubleArray::cast(object->elements());
4676 HeapNumber* number = HeapNumber::cast(*value);
4677 double_array->set(store_index, number->Number());
4678 } else {
4679 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4680 elements_kind == FAST_DOUBLE_ELEMENTS);
4681 TransitionElementsKind(object, FAST_ELEMENTS);
4682 FixedArray* object_array =
4683 FixedArray::cast(object->elements());
4684 object_array->set(store_index, *value);
4685 }
4686 return *object;
4687}
4688
4689
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004690// Set a local property, even if it is READ_ONLY. If the property does not
4691// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004692RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004693 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004694 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004695 CONVERT_CHECKED(JSObject, object, args[0]);
4696 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004697 // Compute attributes.
4698 PropertyAttributes attributes = NONE;
4699 if (args.length() == 4) {
4700 CONVERT_CHECKED(Smi, value_obj, args[3]);
4701 int unchecked_value = value_obj->value();
4702 // Only attribute bits should be set.
4703 RUNTIME_ASSERT(
4704 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4705 attributes = static_cast<PropertyAttributes>(unchecked_value);
4706 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004707
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004708 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004709 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004710}
4711
4712
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004713RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004714 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004715 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004716
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004717 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004718 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004719 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004720 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004721 ? JSReceiver::STRICT_DELETION
4722 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004723}
4724
4725
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004726static Object* HasLocalPropertyImplementation(Isolate* isolate,
4727 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004728 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004729 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004730 // Handle hidden prototypes. If there's a hidden prototype above this thing
4731 // then we have to check it for properties, because they are supposed to
4732 // look like they are on this object.
4733 Handle<Object> proto(object->GetPrototype());
4734 if (proto->IsJSObject() &&
4735 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004736 return HasLocalPropertyImplementation(isolate,
4737 Handle<JSObject>::cast(proto),
4738 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004739 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004740 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004741}
4742
4743
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004744RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004745 NoHandleAllocation ha;
4746 ASSERT(args.length() == 2);
4747 CONVERT_CHECKED(String, key, args[1]);
4748
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004749 uint32_t index;
4750 const bool key_is_array_index = key->AsArrayIndex(&index);
4751
ager@chromium.org9085a012009-05-11 19:22:57 +00004752 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004753 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004754 if (obj->IsJSObject()) {
4755 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004756 // Fast case: either the key is a real named property or it is not
4757 // an array index and there are no interceptors or hidden
4758 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004759 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004760 Map* map = object->map();
4761 if (!key_is_array_index &&
4762 !map->has_named_interceptor() &&
4763 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4764 return isolate->heap()->false_value();
4765 }
4766 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004767 HandleScope scope(isolate);
4768 return HasLocalPropertyImplementation(isolate,
4769 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004770 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004771 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004772 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004773 String* string = String::cast(obj);
4774 if (index < static_cast<uint32_t>(string->length())) {
4775 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004776 }
4777 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004778 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004779}
4780
4781
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004782RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004783 NoHandleAllocation na;
4784 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004785 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4786 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004787
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004788 bool result = receiver->HasProperty(key);
4789 if (isolate->has_pending_exception()) return Failure::Exception();
4790 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004791}
4792
4793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004794RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004795 NoHandleAllocation na;
4796 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004797 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4798 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004799
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004800 bool result = receiver->HasElement(index->value());
4801 if (isolate->has_pending_exception()) return Failure::Exception();
4802 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004803}
4804
4805
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004806RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004807 NoHandleAllocation ha;
4808 ASSERT(args.length() == 2);
4809
4810 CONVERT_CHECKED(JSObject, object, args[0]);
4811 CONVERT_CHECKED(String, key, args[1]);
4812
4813 uint32_t index;
4814 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004815 JSObject::LocalElementType type = object->HasLocalElement(index);
4816 switch (type) {
4817 case JSObject::UNDEFINED_ELEMENT:
4818 case JSObject::STRING_CHARACTER_ELEMENT:
4819 return isolate->heap()->false_value();
4820 case JSObject::INTERCEPTED_ELEMENT:
4821 case JSObject::FAST_ELEMENT:
4822 return isolate->heap()->true_value();
4823 case JSObject::DICTIONARY_ELEMENT: {
4824 if (object->IsJSGlobalProxy()) {
4825 Object* proto = object->GetPrototype();
4826 if (proto->IsNull()) {
4827 return isolate->heap()->false_value();
4828 }
4829 ASSERT(proto->IsJSGlobalObject());
4830 object = JSObject::cast(proto);
4831 }
4832 FixedArray* elements = FixedArray::cast(object->elements());
4833 NumberDictionary* dictionary = NULL;
4834 if (elements->map() ==
4835 isolate->heap()->non_strict_arguments_elements_map()) {
4836 dictionary = NumberDictionary::cast(elements->get(1));
4837 } else {
4838 dictionary = NumberDictionary::cast(elements);
4839 }
4840 int entry = dictionary->FindEntry(index);
4841 ASSERT(entry != NumberDictionary::kNotFound);
4842 PropertyDetails details = dictionary->DetailsAt(entry);
4843 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4844 }
4845 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004846 }
4847
ager@chromium.org870a0b62008-11-04 11:43:05 +00004848 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004849 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004850}
4851
4852
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004853RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004854 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004855 ASSERT(args.length() == 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004856 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4857 bool threw = false;
4858 Handle<JSArray> result = GetKeysFor(object, &threw);
4859 if (threw) return Failure::Exception();
4860 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004861}
4862
4863
4864// Returns either a FixedArray as Runtime_GetPropertyNames,
4865// or, if the given object has an enum cache that contains
4866// all enumerable properties of the object and its prototypes
4867// have none, the map of the object. This is used to speed up
4868// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004869RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004870 ASSERT(args.length() == 1);
4871
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004872 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004873
4874 if (raw_object->IsSimpleEnum()) return raw_object->map();
4875
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004876 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004877 Handle<JSReceiver> object(raw_object);
4878 bool threw = false;
4879 Handle<FixedArray> content =
4880 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4881 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004882
4883 // Test again, since cache may have been built by preceding call.
4884 if (object->IsSimpleEnum()) return object->map();
4885
4886 return *content;
4887}
4888
4889
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004890// Find the length of the prototype chain that is to to handled as one. If a
4891// prototype object is hidden it is to be viewed as part of the the object it
4892// is prototype for.
4893static int LocalPrototypeChainLength(JSObject* obj) {
4894 int count = 1;
4895 Object* proto = obj->GetPrototype();
4896 while (proto->IsJSObject() &&
4897 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4898 count++;
4899 proto = JSObject::cast(proto)->GetPrototype();
4900 }
4901 return count;
4902}
4903
4904
4905// Return the names of the local named properties.
4906// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004907RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004908 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004909 ASSERT(args.length() == 1);
4910 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004911 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004912 }
4913 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4914
4915 // Skip the global proxy as it has no properties and always delegates to the
4916 // real global object.
4917 if (obj->IsJSGlobalProxy()) {
4918 // Only collect names if access is permitted.
4919 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004920 !isolate->MayNamedAccess(*obj,
4921 isolate->heap()->undefined_value(),
4922 v8::ACCESS_KEYS)) {
4923 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4924 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004925 }
4926 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4927 }
4928
4929 // Find the number of objects making up this.
4930 int length = LocalPrototypeChainLength(*obj);
4931
4932 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004933 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004934 int total_property_count = 0;
4935 Handle<JSObject> jsproto = obj;
4936 for (int i = 0; i < length; i++) {
4937 // Only collect names if access is permitted.
4938 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004939 !isolate->MayNamedAccess(*jsproto,
4940 isolate->heap()->undefined_value(),
4941 v8::ACCESS_KEYS)) {
4942 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4943 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004944 }
4945 int n;
4946 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4947 local_property_count[i] = n;
4948 total_property_count += n;
4949 if (i < length - 1) {
4950 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4951 }
4952 }
4953
4954 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004955 Handle<FixedArray> names =
4956 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004957
4958 // Get the property names.
4959 jsproto = obj;
4960 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004961 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004962 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004963 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4964 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004965 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004966 proto_with_hidden_properties++;
4967 }
4968 if (i < length - 1) {
4969 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4970 }
4971 }
4972
4973 // Filter out name of hidden propeties object.
4974 if (proto_with_hidden_properties > 0) {
4975 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004976 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004977 names->length() - proto_with_hidden_properties);
4978 int dest_pos = 0;
4979 for (int i = 0; i < total_property_count; i++) {
4980 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004981 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004982 continue;
4983 }
4984 names->set(dest_pos++, name);
4985 }
4986 }
4987
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004988 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004989}
4990
4991
4992// Return the names of the local indexed properties.
4993// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004994RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004995 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004996 ASSERT(args.length() == 1);
4997 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004998 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004999 }
5000 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5001
5002 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005003 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005004 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005005 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005006}
5007
5008
5009// Return information on whether an object has a named or indexed interceptor.
5010// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005011RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005012 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005013 ASSERT(args.length() == 1);
5014 if (!args[0]->IsJSObject()) {
5015 return Smi::FromInt(0);
5016 }
5017 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5018
5019 int result = 0;
5020 if (obj->HasNamedInterceptor()) result |= 2;
5021 if (obj->HasIndexedInterceptor()) result |= 1;
5022
5023 return Smi::FromInt(result);
5024}
5025
5026
5027// Return property names from named interceptor.
5028// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005029RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005030 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005031 ASSERT(args.length() == 1);
5032 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5033
5034 if (obj->HasNamedInterceptor()) {
5035 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5036 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5037 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005038 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005039}
5040
5041
5042// Return element names from indexed interceptor.
5043// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005044RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005045 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005046 ASSERT(args.length() == 1);
5047 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5048
5049 if (obj->HasIndexedInterceptor()) {
5050 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5051 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5052 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005053 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005054}
5055
5056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005057RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005058 ASSERT_EQ(args.length(), 1);
5059 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005060 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005061 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005062
5063 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005064 // Do access checks before going to the global object.
5065 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005066 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005067 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005068 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5069 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005070 }
5071
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005072 Handle<Object> proto(object->GetPrototype());
5073 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005074 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005075 object = Handle<JSObject>::cast(proto);
5076 }
5077
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005078 bool threw = false;
5079 Handle<FixedArray> contents =
5080 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5081 if (threw) return Failure::Exception();
5082
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005083 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5084 // property array and since the result is mutable we have to create
5085 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005086 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005087 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005088 for (int i = 0; i < length; i++) {
5089 Object* entry = contents->get(i);
5090 if (entry->IsString()) {
5091 copy->set(i, entry);
5092 } else {
5093 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005094 HandleScope scope(isolate);
5095 Handle<Object> entry_handle(entry, isolate);
5096 Handle<Object> entry_str =
5097 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005098 copy->set(i, *entry_str);
5099 }
5100 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005101 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005102}
5103
5104
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005105RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005106 NoHandleAllocation ha;
5107 ASSERT(args.length() == 1);
5108
5109 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005110 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005111 it.AdvanceToArgumentsFrame();
5112 JavaScriptFrame* frame = it.frame();
5113
5114 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005115 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005116
5117 // Try to convert the key to an index. If successful and within
5118 // index return the the argument from the frame.
5119 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005120 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005121 return frame->GetParameter(index);
5122 }
5123
5124 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005125 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005126 bool exception = false;
5127 Handle<Object> converted =
5128 Execution::ToString(args.at<Object>(0), &exception);
5129 if (exception) return Failure::Exception();
5130 Handle<String> key = Handle<String>::cast(converted);
5131
5132 // Try to convert the string key into an array index.
5133 if (key->AsArrayIndex(&index)) {
5134 if (index < n) {
5135 return frame->GetParameter(index);
5136 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005137 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005138 }
5139 }
5140
5141 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005142 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5143 if (key->Equals(isolate->heap()->callee_symbol())) {
5144 Object* function = frame->function();
5145 if (function->IsJSFunction() &&
5146 JSFunction::cast(function)->shared()->strict_mode()) {
5147 return isolate->Throw(*isolate->factory()->NewTypeError(
5148 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5149 }
5150 return function;
5151 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005152
5153 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005154 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005155}
5156
5157
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005158RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005159 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005160
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005161 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005162 Handle<Object> object = args.at<Object>(0);
5163 if (object->IsJSObject()) {
5164 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00005165 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005166 MaybeObject* ok = js_object->TransformToFastProperties(0);
5167 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00005168 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005169 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005170 return *object;
5171}
5172
5173
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005174RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005175 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005176
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005177 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005178 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005179 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005180 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005181 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005182 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005183 return *object;
5184}
5185
5186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005187RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005188 NoHandleAllocation ha;
5189 ASSERT(args.length() == 1);
5190
5191 return args[0]->ToBoolean();
5192}
5193
5194
5195// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5196// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005197RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005198 NoHandleAllocation ha;
5199
5200 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005201 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005202 HeapObject* heap_obj = HeapObject::cast(obj);
5203
5204 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005205 if (heap_obj->map()->is_undetectable()) {
5206 return isolate->heap()->undefined_symbol();
5207 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005208
5209 InstanceType instance_type = heap_obj->map()->instance_type();
5210 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005211 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005212 }
5213
5214 switch (instance_type) {
5215 case ODDBALL_TYPE:
5216 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005217 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005218 }
5219 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005220 return FLAG_harmony_typeof
5221 ? isolate->heap()->null_symbol()
5222 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005223 }
5224 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005225 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005226 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005227 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005228 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005229 default:
5230 // For any kind of object not handled above, the spec rule for
5231 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005232 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005233 }
5234}
5235
5236
lrn@chromium.org25156de2010-04-06 13:10:27 +00005237static bool AreDigits(const char*s, int from, int to) {
5238 for (int i = from; i < to; i++) {
5239 if (s[i] < '0' || s[i] > '9') return false;
5240 }
5241
5242 return true;
5243}
5244
5245
5246static int ParseDecimalInteger(const char*s, int from, int to) {
5247 ASSERT(to - from < 10); // Overflow is not possible.
5248 ASSERT(from < to);
5249 int d = s[from] - '0';
5250
5251 for (int i = from + 1; i < to; i++) {
5252 d = 10 * d + (s[i] - '0');
5253 }
5254
5255 return d;
5256}
5257
5258
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005259RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005260 NoHandleAllocation ha;
5261 ASSERT(args.length() == 1);
5262 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005263 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005264
5265 // Fast case: short integer or some sorts of junk values.
5266 int len = subject->length();
5267 if (subject->IsSeqAsciiString()) {
5268 if (len == 0) return Smi::FromInt(0);
5269
5270 char const* data = SeqAsciiString::cast(subject)->GetChars();
5271 bool minus = (data[0] == '-');
5272 int start_pos = (minus ? 1 : 0);
5273
5274 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005275 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005276 } else if (data[start_pos] > '9') {
5277 // Fast check for a junk value. A valid string may start from a
5278 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5279 // the 'I' character ('Infinity'). All of that have codes not greater than
5280 // '9' except 'I'.
5281 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005282 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005283 }
5284 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5285 // The maximal/minimal smi has 10 digits. If the string has less digits we
5286 // know it will fit into the smi-data type.
5287 int d = ParseDecimalInteger(data, start_pos, len);
5288 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005289 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005290 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005291 } else if (!subject->HasHashCode() &&
5292 len <= String::kMaxArrayIndexSize &&
5293 (len == 1 || data[0] != '0')) {
5294 // String hash is not calculated yet but all the data are present.
5295 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005296 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005297#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005298 subject->Hash(); // Force hash calculation.
5299 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5300 static_cast<int>(hash));
5301#endif
5302 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005303 }
5304 return Smi::FromInt(d);
5305 }
5306 }
5307
5308 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005309 return isolate->heap()->NumberFromDouble(
5310 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005311}
5312
5313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005314RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005315 NoHandleAllocation ha;
5316 ASSERT(args.length() == 1);
5317
5318 CONVERT_CHECKED(JSArray, codes, args[0]);
5319 int length = Smi::cast(codes->length())->value();
5320
5321 // Check if the string can be ASCII.
5322 int i;
5323 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005324 Object* element;
5325 { MaybeObject* maybe_element = codes->GetElement(i);
5326 // We probably can't get an exception here, but just in order to enforce
5327 // the checking of inputs in the runtime calls we check here.
5328 if (!maybe_element->ToObject(&element)) return maybe_element;
5329 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005330 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5331 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5332 break;
5333 }
5334
lrn@chromium.org303ada72010-10-27 09:33:13 +00005335 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005336 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005337 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005338 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005339 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005340 }
5341
lrn@chromium.org303ada72010-10-27 09:33:13 +00005342 Object* object = NULL;
5343 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005344 String* result = String::cast(object);
5345 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005346 Object* element;
5347 { MaybeObject* maybe_element = codes->GetElement(i);
5348 if (!maybe_element->ToObject(&element)) return maybe_element;
5349 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005350 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005351 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005352 }
5353 return result;
5354}
5355
5356
5357// kNotEscaped is generated by the following:
5358//
5359// #!/bin/perl
5360// for (my $i = 0; $i < 256; $i++) {
5361// print "\n" if $i % 16 == 0;
5362// my $c = chr($i);
5363// my $escaped = 1;
5364// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5365// print $escaped ? "0, " : "1, ";
5366// }
5367
5368
5369static bool IsNotEscaped(uint16_t character) {
5370 // Only for 8 bit characters, the rest are always escaped (in a different way)
5371 ASSERT(character < 256);
5372 static const char kNotEscaped[256] = {
5373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5376 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5377 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5378 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5379 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5380 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5385 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5386 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5387 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5388 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5389 };
5390 return kNotEscaped[character] != 0;
5391}
5392
5393
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005394RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005395 const char hex_chars[] = "0123456789ABCDEF";
5396 NoHandleAllocation ha;
5397 ASSERT(args.length() == 1);
5398 CONVERT_CHECKED(String, source, args[0]);
5399
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005400 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005401
5402 int escaped_length = 0;
5403 int length = source->length();
5404 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005405 Access<StringInputBuffer> buffer(
5406 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005407 buffer->Reset(source);
5408 while (buffer->has_more()) {
5409 uint16_t character = buffer->GetNext();
5410 if (character >= 256) {
5411 escaped_length += 6;
5412 } else if (IsNotEscaped(character)) {
5413 escaped_length++;
5414 } else {
5415 escaped_length += 3;
5416 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005417 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005418 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005419 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005420 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005421 return Failure::OutOfMemoryException();
5422 }
5423 }
5424 }
5425 // No length change implies no change. Return original string if no change.
5426 if (escaped_length == length) {
5427 return source;
5428 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005429 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005430 { MaybeObject* maybe_o =
5431 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005432 if (!maybe_o->ToObject(&o)) return maybe_o;
5433 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005434 String* destination = String::cast(o);
5435 int dest_position = 0;
5436
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005437 Access<StringInputBuffer> buffer(
5438 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005439 buffer->Rewind();
5440 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005441 uint16_t chr = buffer->GetNext();
5442 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005443 destination->Set(dest_position, '%');
5444 destination->Set(dest_position+1, 'u');
5445 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5446 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5447 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5448 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005449 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005450 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005451 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005452 dest_position++;
5453 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005454 destination->Set(dest_position, '%');
5455 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5456 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005457 dest_position += 3;
5458 }
5459 }
5460 return destination;
5461}
5462
5463
5464static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5465 static const signed char kHexValue['g'] = {
5466 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5467 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5468 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5469 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5470 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5471 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5472 -1, 10, 11, 12, 13, 14, 15 };
5473
5474 if (character1 > 'f') return -1;
5475 int hi = kHexValue[character1];
5476 if (hi == -1) return -1;
5477 if (character2 > 'f') return -1;
5478 int lo = kHexValue[character2];
5479 if (lo == -1) return -1;
5480 return (hi << 4) + lo;
5481}
5482
5483
ager@chromium.org870a0b62008-11-04 11:43:05 +00005484static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005485 int i,
5486 int length,
5487 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005488 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005489 int32_t hi = 0;
5490 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005491 if (character == '%' &&
5492 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005493 source->Get(i + 1) == 'u' &&
5494 (hi = TwoDigitHex(source->Get(i + 2),
5495 source->Get(i + 3))) != -1 &&
5496 (lo = TwoDigitHex(source->Get(i + 4),
5497 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005498 *step = 6;
5499 return (hi << 8) + lo;
5500 } else if (character == '%' &&
5501 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005502 (lo = TwoDigitHex(source->Get(i + 1),
5503 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005504 *step = 3;
5505 return lo;
5506 } else {
5507 *step = 1;
5508 return character;
5509 }
5510}
5511
5512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005513RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005514 NoHandleAllocation ha;
5515 ASSERT(args.length() == 1);
5516 CONVERT_CHECKED(String, source, args[0]);
5517
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005518 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005519
5520 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005521 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005522
5523 int unescaped_length = 0;
5524 for (int i = 0; i < length; unescaped_length++) {
5525 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005526 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005527 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005528 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005529 i += step;
5530 }
5531
5532 // No length change implies no change. Return original string if no change.
5533 if (unescaped_length == length)
5534 return source;
5535
lrn@chromium.org303ada72010-10-27 09:33:13 +00005536 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005537 { MaybeObject* maybe_o =
5538 ascii ?
5539 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5540 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005541 if (!maybe_o->ToObject(&o)) return maybe_o;
5542 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005543 String* destination = String::cast(o);
5544
5545 int dest_position = 0;
5546 for (int i = 0; i < length; dest_position++) {
5547 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005548 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005549 i += step;
5550 }
5551 return destination;
5552}
5553
5554
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005555static const unsigned int kQuoteTableLength = 128u;
5556
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005557static const int kJsonQuotesCharactersPerEntry = 8;
5558static const char* const JsonQuotes =
5559 "\\u0000 \\u0001 \\u0002 \\u0003 "
5560 "\\u0004 \\u0005 \\u0006 \\u0007 "
5561 "\\b \\t \\n \\u000b "
5562 "\\f \\r \\u000e \\u000f "
5563 "\\u0010 \\u0011 \\u0012 \\u0013 "
5564 "\\u0014 \\u0015 \\u0016 \\u0017 "
5565 "\\u0018 \\u0019 \\u001a \\u001b "
5566 "\\u001c \\u001d \\u001e \\u001f "
5567 " ! \\\" # "
5568 "$ % & ' "
5569 "( ) * + "
5570 ", - . / "
5571 "0 1 2 3 "
5572 "4 5 6 7 "
5573 "8 9 : ; "
5574 "< = > ? "
5575 "@ A B C "
5576 "D E F G "
5577 "H I J K "
5578 "L M N O "
5579 "P Q R S "
5580 "T U V W "
5581 "X Y Z [ "
5582 "\\\\ ] ^ _ "
5583 "` a b c "
5584 "d e f g "
5585 "h i j k "
5586 "l m n o "
5587 "p q r s "
5588 "t u v w "
5589 "x y z { "
5590 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005591
5592
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005593// For a string that is less than 32k characters it should always be
5594// possible to allocate it in new space.
5595static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5596
5597
5598// Doing JSON quoting cannot make the string more than this many times larger.
5599static const int kJsonQuoteWorstCaseBlowup = 6;
5600
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005601static const int kSpaceForQuotesAndComma = 3;
5602static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005603
5604// Covers the entire ASCII range (all other characters are unchanged by JSON
5605// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005606static const byte JsonQuoteLengths[kQuoteTableLength] = {
5607 6, 6, 6, 6, 6, 6, 6, 6,
5608 2, 2, 2, 6, 2, 2, 6, 6,
5609 6, 6, 6, 6, 6, 6, 6, 6,
5610 6, 6, 6, 6, 6, 6, 6, 6,
5611 1, 1, 2, 1, 1, 1, 1, 1,
5612 1, 1, 1, 1, 1, 1, 1, 1,
5613 1, 1, 1, 1, 1, 1, 1, 1,
5614 1, 1, 1, 1, 1, 1, 1, 1,
5615 1, 1, 1, 1, 1, 1, 1, 1,
5616 1, 1, 1, 1, 1, 1, 1, 1,
5617 1, 1, 1, 1, 1, 1, 1, 1,
5618 1, 1, 1, 1, 2, 1, 1, 1,
5619 1, 1, 1, 1, 1, 1, 1, 1,
5620 1, 1, 1, 1, 1, 1, 1, 1,
5621 1, 1, 1, 1, 1, 1, 1, 1,
5622 1, 1, 1, 1, 1, 1, 1, 1,
5623};
5624
5625
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005626template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005627MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005628
5629
5630template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005631MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5632 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005633}
5634
5635
5636template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005637MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5638 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005639}
5640
5641
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005642template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005643static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5644 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005645 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005646 const Char* read_cursor = characters.start();
5647 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005648 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005649 int quoted_length = kSpaceForQuotes;
5650 while (read_cursor < end) {
5651 Char c = *(read_cursor++);
5652 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5653 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005654 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005655 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005656 }
5657 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005658 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5659 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005660 Object* new_object;
5661 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005662 return new_alloc;
5663 }
5664 StringType* new_string = StringType::cast(new_object);
5665
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005666 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005667 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005668 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005669 *(write_cursor++) = '"';
5670
5671 read_cursor = characters.start();
5672 while (read_cursor < end) {
5673 Char c = *(read_cursor++);
5674 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5675 *(write_cursor++) = c;
5676 } else {
5677 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5678 const char* replacement = JsonQuotes +
5679 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5680 for (int i = 0; i < len; i++) {
5681 *write_cursor++ = *replacement++;
5682 }
5683 }
5684 }
5685 *(write_cursor++) = '"';
5686 return new_string;
5687}
5688
5689
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005690template <typename SinkChar, typename SourceChar>
5691static inline SinkChar* WriteQuoteJsonString(
5692 Isolate* isolate,
5693 SinkChar* write_cursor,
5694 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005695 // SinkChar is only char if SourceChar is guaranteed to be char.
5696 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005697 const SourceChar* read_cursor = characters.start();
5698 const SourceChar* end = read_cursor + characters.length();
5699 *(write_cursor++) = '"';
5700 while (read_cursor < end) {
5701 SourceChar c = *(read_cursor++);
5702 if (sizeof(SourceChar) > 1u &&
5703 static_cast<unsigned>(c) >= kQuoteTableLength) {
5704 *(write_cursor++) = static_cast<SinkChar>(c);
5705 } else {
5706 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5707 const char* replacement = JsonQuotes +
5708 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5709 write_cursor[0] = replacement[0];
5710 if (len > 1) {
5711 write_cursor[1] = replacement[1];
5712 if (len > 2) {
5713 ASSERT(len == 6);
5714 write_cursor[2] = replacement[2];
5715 write_cursor[3] = replacement[3];
5716 write_cursor[4] = replacement[4];
5717 write_cursor[5] = replacement[5];
5718 }
5719 }
5720 write_cursor += len;
5721 }
5722 }
5723 *(write_cursor++) = '"';
5724 return write_cursor;
5725}
5726
5727
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005728template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005729static MaybeObject* QuoteJsonString(Isolate* isolate,
5730 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005731 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005732 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005733 int worst_case_length =
5734 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005735 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005736 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005737 }
5738
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005739 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5740 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005741 Object* new_object;
5742 if (!new_alloc->ToObject(&new_object)) {
5743 return new_alloc;
5744 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005745 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005746 // Even if our string is small enough to fit in new space we still have to
5747 // handle it being allocated in old space as may happen in the third
5748 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5749 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005750 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005751 }
5752 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005753 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005754
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005755 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005756 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005757 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005758 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5759 write_cursor,
5760 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005761 int final_length = static_cast<int>(
5762 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005763 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005764 isolate->heap()->new_space()->
5765 template ShrinkStringAtAllocationBoundary<StringType>(
5766 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005767 return new_string;
5768}
5769
5770
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005771RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005772 NoHandleAllocation ha;
5773 CONVERT_CHECKED(String, str, args[0]);
5774 if (!str->IsFlat()) {
5775 MaybeObject* try_flatten = str->TryFlatten();
5776 Object* flat;
5777 if (!try_flatten->ToObject(&flat)) {
5778 return try_flatten;
5779 }
5780 str = String::cast(flat);
5781 ASSERT(str->IsFlat());
5782 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005783 String::FlatContent flat = str->GetFlatContent();
5784 ASSERT(flat.IsFlat());
5785 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005786 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005787 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005788 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005789 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005790 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005791 }
5792}
5793
5794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005795RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005796 NoHandleAllocation ha;
5797 CONVERT_CHECKED(String, str, args[0]);
5798 if (!str->IsFlat()) {
5799 MaybeObject* try_flatten = str->TryFlatten();
5800 Object* flat;
5801 if (!try_flatten->ToObject(&flat)) {
5802 return try_flatten;
5803 }
5804 str = String::cast(flat);
5805 ASSERT(str->IsFlat());
5806 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005807 String::FlatContent flat = str->GetFlatContent();
5808 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005809 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005810 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005811 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005812 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005813 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005814 }
5815}
5816
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005817
5818template <typename Char, typename StringType>
5819static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5820 FixedArray* array,
5821 int worst_case_length) {
5822 int length = array->length();
5823
5824 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5825 worst_case_length);
5826 Object* new_object;
5827 if (!new_alloc->ToObject(&new_object)) {
5828 return new_alloc;
5829 }
5830 if (!isolate->heap()->new_space()->Contains(new_object)) {
5831 // Even if our string is small enough to fit in new space we still have to
5832 // handle it being allocated in old space as may happen in the third
5833 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5834 // CEntryStub::GenerateCore.
5835 return isolate->heap()->undefined_value();
5836 }
5837 AssertNoAllocation no_gc;
5838 StringType* new_string = StringType::cast(new_object);
5839 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5840
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005841 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005842 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005843 *(write_cursor++) = '[';
5844 for (int i = 0; i < length; i++) {
5845 if (i != 0) *(write_cursor++) = ',';
5846 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005847 String::FlatContent content = str->GetFlatContent();
5848 ASSERT(content.IsFlat());
5849 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005850 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5851 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005852 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005853 } else {
5854 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5855 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005856 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005857 }
5858 }
5859 *(write_cursor++) = ']';
5860
5861 int final_length = static_cast<int>(
5862 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005863 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005864 isolate->heap()->new_space()->
5865 template ShrinkStringAtAllocationBoundary<StringType>(
5866 new_string, final_length);
5867 return new_string;
5868}
5869
5870
5871RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5872 NoHandleAllocation ha;
5873 ASSERT(args.length() == 1);
5874 CONVERT_CHECKED(JSArray, array, args[0]);
5875
5876 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5877 FixedArray* elements = FixedArray::cast(array->elements());
5878 int n = elements->length();
5879 bool ascii = true;
5880 int total_length = 0;
5881
5882 for (int i = 0; i < n; i++) {
5883 Object* elt = elements->get(i);
5884 if (!elt->IsString()) return isolate->heap()->undefined_value();
5885 String* element = String::cast(elt);
5886 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5887 total_length += element->length();
5888 if (ascii && element->IsTwoByteRepresentation()) {
5889 ascii = false;
5890 }
5891 }
5892
5893 int worst_case_length =
5894 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5895 + total_length * kJsonQuoteWorstCaseBlowup;
5896
5897 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5898 return isolate->heap()->undefined_value();
5899 }
5900
5901 if (ascii) {
5902 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5903 elements,
5904 worst_case_length);
5905 } else {
5906 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5907 elements,
5908 worst_case_length);
5909 }
5910}
5911
5912
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005913RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005914 NoHandleAllocation ha;
5915
5916 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005917 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005919 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005920
lrn@chromium.org25156de2010-04-06 13:10:27 +00005921 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005922 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005923 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005924}
5925
5926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005927RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005928 NoHandleAllocation ha;
5929 CONVERT_CHECKED(String, str, args[0]);
5930
5931 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005932 double value = StringToDouble(isolate->unicode_cache(),
5933 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005934
5935 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005936 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005937}
5938
5939
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005940template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005941MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005942 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005943 String* s,
5944 int length,
5945 int input_string_length,
5946 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005947 // We try this twice, once with the assumption that the result is no longer
5948 // than the input and, if that assumption breaks, again with the exact
5949 // length. This may not be pretty, but it is nicer than what was here before
5950 // and I hereby claim my vaffel-is.
5951 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005952 // Allocate the resulting string.
5953 //
5954 // NOTE: This assumes that the upper/lower case of an ascii
5955 // character is also ascii. This is currently the case, but it
5956 // might break in the future if we implement more context and locale
5957 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005958 Object* o;
5959 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005960 ? isolate->heap()->AllocateRawAsciiString(length)
5961 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005962 if (!maybe_o->ToObject(&o)) return maybe_o;
5963 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005964 String* result = String::cast(o);
5965 bool has_changed_character = false;
5966
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005967 // Convert all characters to upper case, assuming that they will fit
5968 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005969 Access<StringInputBuffer> buffer(
5970 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005971 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005972 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005973 // We can assume that the string is not empty
5974 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005975 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005976 bool has_next = buffer->has_more();
5977 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005978 int char_length = mapping->get(current, next, chars);
5979 if (char_length == 0) {
5980 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005981 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982 i++;
5983 } else if (char_length == 1) {
5984 // Common case: converting the letter resulted in one character.
5985 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005986 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005987 has_changed_character = true;
5988 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005989 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005990 // We've assumed that the result would be as long as the
5991 // input but here is a character that converts to several
5992 // characters. No matter, we calculate the exact length
5993 // of the result and try the whole thing again.
5994 //
5995 // Note that this leaves room for optimization. We could just
5996 // memcpy what we already have to the result string. Also,
5997 // the result string is the last object allocated we could
5998 // "realloc" it and probably, in the vast majority of cases,
5999 // extend the existing string to be able to hold the full
6000 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006001 int next_length = 0;
6002 if (has_next) {
6003 next_length = mapping->get(next, 0, chars);
6004 if (next_length == 0) next_length = 1;
6005 }
6006 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006007 while (buffer->has_more()) {
6008 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006009 // NOTE: we use 0 as the next character here because, while
6010 // the next character may affect what a character converts to,
6011 // it does not in any case affect the length of what it convert
6012 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006013 int char_length = mapping->get(current, 0, chars);
6014 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006015 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006016 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006017 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006018 return Failure::OutOfMemoryException();
6019 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006020 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006021 // Try again with the real length.
6022 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006023 } else {
6024 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006025 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026 i++;
6027 }
6028 has_changed_character = true;
6029 }
6030 current = next;
6031 }
6032 if (has_changed_character) {
6033 return result;
6034 } else {
6035 // If we didn't actually change anything in doing the conversion
6036 // we simple return the result and let the converted string
6037 // become garbage; there is no reason to keep two identical strings
6038 // alive.
6039 return s;
6040 }
6041}
6042
6043
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006044namespace {
6045
lrn@chromium.org303ada72010-10-27 09:33:13 +00006046static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6047
6048
6049// Given a word and two range boundaries returns a word with high bit
6050// set in every byte iff the corresponding input byte was strictly in
6051// the range (m, n). All the other bits in the result are cleared.
6052// This function is only useful when it can be inlined and the
6053// boundaries are statically known.
6054// Requires: all bytes in the input word and the boundaries must be
6055// ascii (less than 0x7F).
6056static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
6057 // Every byte in an ascii string is less than or equal to 0x7F.
6058 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6059 // Use strict inequalities since in edge cases the function could be
6060 // further simplified.
6061 ASSERT(0 < m && m < n && n < 0x7F);
6062 // Has high bit set in every w byte less than n.
6063 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6064 // Has high bit set in every w byte greater than m.
6065 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6066 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6067}
6068
6069
6070enum AsciiCaseConversion {
6071 ASCII_TO_LOWER,
6072 ASCII_TO_UPPER
6073};
6074
6075
6076template <AsciiCaseConversion dir>
6077struct FastAsciiConverter {
6078 static bool Convert(char* dst, char* src, int length) {
6079#ifdef DEBUG
6080 char* saved_dst = dst;
6081 char* saved_src = src;
6082#endif
6083 // We rely on the distance between upper and lower case letters
6084 // being a known power of 2.
6085 ASSERT('a' - 'A' == (1 << 5));
6086 // Boundaries for the range of input characters than require conversion.
6087 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6088 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6089 bool changed = false;
6090 char* const limit = src + length;
6091#ifdef V8_HOST_CAN_READ_UNALIGNED
6092 // Process the prefix of the input that requires no conversion one
6093 // (machine) word at a time.
6094 while (src <= limit - sizeof(uintptr_t)) {
6095 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6096 if (AsciiRangeMask(w, lo, hi) != 0) {
6097 changed = true;
6098 break;
6099 }
6100 *reinterpret_cast<uintptr_t*>(dst) = w;
6101 src += sizeof(uintptr_t);
6102 dst += sizeof(uintptr_t);
6103 }
6104 // Process the remainder of the input performing conversion when
6105 // required one word at a time.
6106 while (src <= limit - sizeof(uintptr_t)) {
6107 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6108 uintptr_t m = AsciiRangeMask(w, lo, hi);
6109 // The mask has high (7th) bit set in every byte that needs
6110 // conversion and we know that the distance between cases is
6111 // 1 << 5.
6112 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6113 src += sizeof(uintptr_t);
6114 dst += sizeof(uintptr_t);
6115 }
6116#endif
6117 // Process the last few bytes of the input (or the whole input if
6118 // unaligned access is not supported).
6119 while (src < limit) {
6120 char c = *src;
6121 if (lo < c && c < hi) {
6122 c ^= (1 << 5);
6123 changed = true;
6124 }
6125 *dst = c;
6126 ++src;
6127 ++dst;
6128 }
6129#ifdef DEBUG
6130 CheckConvert(saved_dst, saved_src, length, changed);
6131#endif
6132 return changed;
6133 }
6134
6135#ifdef DEBUG
6136 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6137 bool expected_changed = false;
6138 for (int i = 0; i < length; i++) {
6139 if (dst[i] == src[i]) continue;
6140 expected_changed = true;
6141 if (dir == ASCII_TO_LOWER) {
6142 ASSERT('A' <= src[i] && src[i] <= 'Z');
6143 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6144 } else {
6145 ASSERT(dir == ASCII_TO_UPPER);
6146 ASSERT('a' <= src[i] && src[i] <= 'z');
6147 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6148 }
6149 }
6150 ASSERT(expected_changed == changed);
6151 }
6152#endif
6153};
6154
6155
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006156struct ToLowerTraits {
6157 typedef unibrow::ToLowercase UnibrowConverter;
6158
lrn@chromium.org303ada72010-10-27 09:33:13 +00006159 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006160};
6161
6162
6163struct ToUpperTraits {
6164 typedef unibrow::ToUppercase UnibrowConverter;
6165
lrn@chromium.org303ada72010-10-27 09:33:13 +00006166 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006167};
6168
6169} // namespace
6170
6171
6172template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006173MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006174 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006175 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006176 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006177 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006178 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006179 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006180
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006181 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006182 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006183 if (length == 0) return s;
6184
6185 // Simpler handling of ascii strings.
6186 //
6187 // NOTE: This assumes that the upper/lower case of an ascii
6188 // character is also ascii. This is currently the case, but it
6189 // might break in the future if we implement more context and locale
6190 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006191 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006192 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006193 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006194 if (!maybe_o->ToObject(&o)) return maybe_o;
6195 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006196 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006197 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006198 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006199 return has_changed_character ? result : s;
6200 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006201
lrn@chromium.org303ada72010-10-27 09:33:13 +00006202 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006203 { MaybeObject* maybe_answer =
6204 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006205 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6206 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006207 if (answer->IsSmi()) {
6208 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006209 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006210 ConvertCaseHelper(isolate,
6211 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006212 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6213 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006214 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006215 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006216}
6217
6218
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006219RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006220 return ConvertCase<ToLowerTraits>(
6221 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006222}
6223
6224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006225RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006226 return ConvertCase<ToUpperTraits>(
6227 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006228}
6229
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006230
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006231static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006232 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006233}
6234
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006236RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006237 NoHandleAllocation ha;
6238 ASSERT(args.length() == 3);
6239
6240 CONVERT_CHECKED(String, s, args[0]);
6241 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6242 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6243
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006244 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006245 int length = s->length();
6246
6247 int left = 0;
6248 if (trimLeft) {
6249 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6250 left++;
6251 }
6252 }
6253
6254 int right = length;
6255 if (trimRight) {
6256 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6257 right--;
6258 }
6259 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006260 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006261}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006262
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006263
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006264RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006265 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006266 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006267 CONVERT_ARG_CHECKED(String, subject, 0);
6268 CONVERT_ARG_CHECKED(String, pattern, 1);
6269 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6270
6271 int subject_length = subject->length();
6272 int pattern_length = pattern->length();
6273 RUNTIME_ASSERT(pattern_length > 0);
6274
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006275 if (limit == 0xffffffffu) {
6276 Handle<Object> cached_answer(StringSplitCache::Lookup(
6277 isolate->heap()->string_split_cache(),
6278 *subject,
6279 *pattern));
6280 if (*cached_answer != Smi::FromInt(0)) {
6281 Handle<JSArray> result =
6282 isolate->factory()->NewJSArrayWithElements(
6283 Handle<FixedArray>::cast(cached_answer));
6284 return *result;
6285 }
6286 }
6287
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006288 // The limit can be very large (0xffffffffu), but since the pattern
6289 // isn't empty, we can never create more parts than ~half the length
6290 // of the subject.
6291
6292 if (!subject->IsFlat()) FlattenString(subject);
6293
6294 static const int kMaxInitialListCapacity = 16;
6295
danno@chromium.org40cb8782011-05-25 07:58:50 +00006296 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006297
6298 // Find (up to limit) indices of separator and end-of-string in subject
6299 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6300 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006301 if (!pattern->IsFlat()) FlattenString(pattern);
6302
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006303 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006304
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006305 if (static_cast<uint32_t>(indices.length()) < limit) {
6306 indices.Add(subject_length);
6307 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006308
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006309 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006310
6311 // Create JSArray of substrings separated by separator.
6312 int part_count = indices.length();
6313
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006314 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006315 MaybeObject* maybe_result = result->EnsureCanContainNonSmiElements();
6316 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006317 result->set_length(Smi::FromInt(part_count));
6318
6319 ASSERT(result->HasFastElements());
6320
6321 if (part_count == 1 && indices.at(0) == subject_length) {
6322 FixedArray::cast(result->elements())->set(0, *subject);
6323 return *result;
6324 }
6325
6326 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6327 int part_start = 0;
6328 for (int i = 0; i < part_count; i++) {
6329 HandleScope local_loop_handle;
6330 int part_end = indices.at(i);
6331 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006332 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006333 elements->set(i, *substring);
6334 part_start = part_end + pattern_length;
6335 }
6336
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006337 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006338 if (result->HasFastElements()) {
6339 StringSplitCache::Enter(isolate->heap(),
6340 isolate->heap()->string_split_cache(),
6341 *subject,
6342 *pattern,
6343 *elements);
6344 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006345 }
6346
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006347 return *result;
6348}
6349
6350
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006351// Copies ascii characters to the given fixed array looking up
6352// one-char strings in the cache. Gives up on the first char that is
6353// not in the cache and fills the remainder with smi zeros. Returns
6354// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006355static int CopyCachedAsciiCharsToArray(Heap* heap,
6356 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006357 FixedArray* elements,
6358 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006359 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006360 FixedArray* ascii_cache = heap->single_character_string_cache();
6361 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006362 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006363 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006364 for (i = 0; i < length; ++i) {
6365 Object* value = ascii_cache->get(chars[i]);
6366 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006367 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006368 }
6369 if (i < length) {
6370 ASSERT(Smi::FromInt(0) == 0);
6371 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6372 }
6373#ifdef DEBUG
6374 for (int j = 0; j < length; ++j) {
6375 Object* element = elements->get(j);
6376 ASSERT(element == Smi::FromInt(0) ||
6377 (element->IsString() && String::cast(element)->LooksValid()));
6378 }
6379#endif
6380 return i;
6381}
6382
6383
6384// Converts a String to JSArray.
6385// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006386RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006387 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006388 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006389 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006390 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006391
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006392 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006393 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006394
6395 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006396 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006397 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006398 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006399 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006400 { MaybeObject* maybe_obj =
6401 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006402 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6403 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006404 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006405 String::FlatContent content = s->GetFlatContent();
6406 if (content.IsAscii()) {
6407 Vector<const char> chars = content.ToAsciiVector();
6408 // Note, this will initialize all elements (not only the prefix)
6409 // to prevent GC from seeing partially initialized array.
6410 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6411 chars.start(),
6412 *elements,
6413 length);
6414 } else {
6415 MemsetPointer(elements->data_start(),
6416 isolate->heap()->undefined_value(),
6417 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006418 }
6419 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006420 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006421 }
6422 for (int i = position; i < length; ++i) {
6423 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6424 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006425 }
6426
6427#ifdef DEBUG
6428 for (int i = 0; i < length; ++i) {
6429 ASSERT(String::cast(elements->get(i))->length() == 1);
6430 }
6431#endif
6432
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006433 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006434}
6435
6436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006437RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006438 NoHandleAllocation ha;
6439 ASSERT(args.length() == 1);
6440 CONVERT_CHECKED(String, value, args[0]);
6441 return value->ToObject();
6442}
6443
6444
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006445bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006446 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006447 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006448 return char_length == 0;
6449}
6450
6451
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006452RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006453 NoHandleAllocation ha;
6454 ASSERT(args.length() == 1);
6455
6456 Object* number = args[0];
6457 RUNTIME_ASSERT(number->IsNumber());
6458
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006459 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006460}
6461
6462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006463RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006464 NoHandleAllocation ha;
6465 ASSERT(args.length() == 1);
6466
6467 Object* number = args[0];
6468 RUNTIME_ASSERT(number->IsNumber());
6469
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006470 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006471}
6472
6473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006474RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006475 NoHandleAllocation ha;
6476 ASSERT(args.length() == 1);
6477
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006478 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006479
6480 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6481 if (number > 0 && number <= Smi::kMaxValue) {
6482 return Smi::FromInt(static_cast<int>(number));
6483 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006484 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006485}
6486
6487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006488RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006489 NoHandleAllocation ha;
6490 ASSERT(args.length() == 1);
6491
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006492 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006493
6494 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6495 if (number > 0 && number <= Smi::kMaxValue) {
6496 return Smi::FromInt(static_cast<int>(number));
6497 }
6498
6499 double double_value = DoubleToInteger(number);
6500 // Map both -0 and +0 to +0.
6501 if (double_value == 0) double_value = 0;
6502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006503 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006504}
6505
6506
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006507RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006508 NoHandleAllocation ha;
6509 ASSERT(args.length() == 1);
6510
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006511 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006512 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006513}
6514
6515
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006516RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006517 NoHandleAllocation ha;
6518 ASSERT(args.length() == 1);
6519
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006520 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006521
6522 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6523 if (number > 0 && number <= Smi::kMaxValue) {
6524 return Smi::FromInt(static_cast<int>(number));
6525 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006526 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006527}
6528
6529
ager@chromium.org870a0b62008-11-04 11:43:05 +00006530// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6531// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006532RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006533 NoHandleAllocation ha;
6534 ASSERT(args.length() == 1);
6535
6536 Object* obj = args[0];
6537 if (obj->IsSmi()) {
6538 return obj;
6539 }
6540 if (obj->IsHeapNumber()) {
6541 double value = HeapNumber::cast(obj)->value();
6542 int int_value = FastD2I(value);
6543 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6544 return Smi::FromInt(int_value);
6545 }
6546 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006547 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006548}
6549
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006551RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006552 NoHandleAllocation ha;
6553 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006554 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006555}
6556
6557
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006558RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006559 NoHandleAllocation ha;
6560 ASSERT(args.length() == 2);
6561
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006562 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6563 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006564 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006565}
6566
6567
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006568RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006569 NoHandleAllocation ha;
6570 ASSERT(args.length() == 2);
6571
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006572 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6573 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006574 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575}
6576
6577
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006578RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006579 NoHandleAllocation ha;
6580 ASSERT(args.length() == 2);
6581
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006582 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6583 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006584 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006585}
6586
6587
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006588RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006589 NoHandleAllocation ha;
6590 ASSERT(args.length() == 1);
6591
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006592 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006593 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006594}
6595
6596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006597RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006598 NoHandleAllocation ha;
6599 ASSERT(args.length() == 0);
6600
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006601 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006602}
6603
6604
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006605RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006606 NoHandleAllocation ha;
6607 ASSERT(args.length() == 2);
6608
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006609 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6610 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006611 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006612}
6613
6614
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006615RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006616 NoHandleAllocation ha;
6617 ASSERT(args.length() == 2);
6618
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006619 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6620 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006621
ager@chromium.org3811b432009-10-28 14:53:37 +00006622 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006623 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006624 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006625}
6626
6627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006628RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629 NoHandleAllocation ha;
6630 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006631 CONVERT_CHECKED(String, str1, args[0]);
6632 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006633 isolate->counters()->string_add_runtime()->Increment();
6634 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006635}
6636
6637
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006638template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006639static inline void StringBuilderConcatHelper(String* special,
6640 sinkchar* sink,
6641 FixedArray* fixed_array,
6642 int array_length) {
6643 int position = 0;
6644 for (int i = 0; i < array_length; i++) {
6645 Object* element = fixed_array->get(i);
6646 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006647 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006648 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006649 int pos;
6650 int len;
6651 if (encoded_slice > 0) {
6652 // Position and length encoded in one smi.
6653 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6654 len = StringBuilderSubstringLength::decode(encoded_slice);
6655 } else {
6656 // Position and length encoded in two smis.
6657 Object* obj = fixed_array->get(++i);
6658 ASSERT(obj->IsSmi());
6659 pos = Smi::cast(obj)->value();
6660 len = -encoded_slice;
6661 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006662 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006663 sink + position,
6664 pos,
6665 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006666 position += len;
6667 } else {
6668 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006669 int element_length = string->length();
6670 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006671 position += element_length;
6672 }
6673 }
6674}
6675
6676
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006677RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006678 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006679 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006680 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006681 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006682 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006683 return Failure::OutOfMemoryException();
6684 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006685 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006686 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006687
6688 // This assumption is used by the slice encoding in one or two smis.
6689 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6690
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006691 MaybeObject* maybe_result = array->EnsureCanContainNonSmiElements();
6692 if (maybe_result->IsFailure()) return maybe_result;
6693
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006694 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006695 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006696 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006697 }
6698 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006699 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006700 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006701 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006702
6703 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006704 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006705 } else if (array_length == 1) {
6706 Object* first = fixed_array->get(0);
6707 if (first->IsString()) return first;
6708 }
6709
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006710 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006711 int position = 0;
6712 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006713 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006714 Object* elt = fixed_array->get(i);
6715 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006716 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006717 int smi_value = Smi::cast(elt)->value();
6718 int pos;
6719 int len;
6720 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006721 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006722 pos = StringBuilderSubstringPosition::decode(smi_value);
6723 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006724 } else {
6725 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006726 len = -smi_value;
6727 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006728 i++;
6729 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006730 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006731 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006732 Object* next_smi = fixed_array->get(i);
6733 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006734 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006735 }
6736 pos = Smi::cast(next_smi)->value();
6737 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006738 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006739 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006741 ASSERT(pos >= 0);
6742 ASSERT(len >= 0);
6743 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006744 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006745 }
6746 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006747 } else if (elt->IsString()) {
6748 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006749 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006750 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006751 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006752 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006753 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006754 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006755 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006756 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006757 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006758 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006759 return Failure::OutOfMemoryException();
6760 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006761 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006762 }
6763
6764 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006765 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006766
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006767 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006768 { MaybeObject* maybe_object =
6769 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006770 if (!maybe_object->ToObject(&object)) return maybe_object;
6771 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006772 SeqAsciiString* answer = SeqAsciiString::cast(object);
6773 StringBuilderConcatHelper(special,
6774 answer->GetChars(),
6775 fixed_array,
6776 array_length);
6777 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006778 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006779 { MaybeObject* maybe_object =
6780 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006781 if (!maybe_object->ToObject(&object)) return maybe_object;
6782 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006783 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6784 StringBuilderConcatHelper(special,
6785 answer->GetChars(),
6786 fixed_array,
6787 array_length);
6788 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006789 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006790}
6791
6792
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006793RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006794 NoHandleAllocation ha;
6795 ASSERT(args.length() == 3);
6796 CONVERT_CHECKED(JSArray, array, args[0]);
6797 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006798 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006799 return Failure::OutOfMemoryException();
6800 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006801 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006802 CONVERT_CHECKED(String, separator, args[2]);
6803
6804 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006805 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006806 }
6807 FixedArray* fixed_array = FixedArray::cast(array->elements());
6808 if (fixed_array->length() < array_length) {
6809 array_length = fixed_array->length();
6810 }
6811
6812 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006813 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006814 } else if (array_length == 1) {
6815 Object* first = fixed_array->get(0);
6816 if (first->IsString()) return first;
6817 }
6818
6819 int separator_length = separator->length();
6820 int max_nof_separators =
6821 (String::kMaxLength + separator_length - 1) / separator_length;
6822 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006823 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006824 return Failure::OutOfMemoryException();
6825 }
6826 int length = (array_length - 1) * separator_length;
6827 for (int i = 0; i < array_length; i++) {
6828 Object* element_obj = fixed_array->get(i);
6829 if (!element_obj->IsString()) {
6830 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006831 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006832 }
6833 String* element = String::cast(element_obj);
6834 int increment = element->length();
6835 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006836 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006837 return Failure::OutOfMemoryException();
6838 }
6839 length += increment;
6840 }
6841
6842 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006843 { MaybeObject* maybe_object =
6844 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006845 if (!maybe_object->ToObject(&object)) return maybe_object;
6846 }
6847 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6848
6849 uc16* sink = answer->GetChars();
6850#ifdef DEBUG
6851 uc16* end = sink + length;
6852#endif
6853
6854 String* first = String::cast(fixed_array->get(0));
6855 int first_length = first->length();
6856 String::WriteToFlat(first, sink, 0, first_length);
6857 sink += first_length;
6858
6859 for (int i = 1; i < array_length; i++) {
6860 ASSERT(sink + separator_length <= end);
6861 String::WriteToFlat(separator, sink, 0, separator_length);
6862 sink += separator_length;
6863
6864 String* element = String::cast(fixed_array->get(i));
6865 int element_length = element->length();
6866 ASSERT(sink + element_length <= end);
6867 String::WriteToFlat(element, sink, 0, element_length);
6868 sink += element_length;
6869 }
6870 ASSERT(sink == end);
6871
6872 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6873 return answer;
6874}
6875
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006876template <typename Char>
6877static void JoinSparseArrayWithSeparator(FixedArray* elements,
6878 int elements_length,
6879 uint32_t array_length,
6880 String* separator,
6881 Vector<Char> buffer) {
6882 int previous_separator_position = 0;
6883 int separator_length = separator->length();
6884 int cursor = 0;
6885 for (int i = 0; i < elements_length; i += 2) {
6886 int position = NumberToInt32(elements->get(i));
6887 String* string = String::cast(elements->get(i + 1));
6888 int string_length = string->length();
6889 if (string->length() > 0) {
6890 while (previous_separator_position < position) {
6891 String::WriteToFlat<Char>(separator, &buffer[cursor],
6892 0, separator_length);
6893 cursor += separator_length;
6894 previous_separator_position++;
6895 }
6896 String::WriteToFlat<Char>(string, &buffer[cursor],
6897 0, string_length);
6898 cursor += string->length();
6899 }
6900 }
6901 if (separator_length > 0) {
6902 // Array length must be representable as a signed 32-bit number,
6903 // otherwise the total string length would have been too large.
6904 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6905 int last_array_index = static_cast<int>(array_length - 1);
6906 while (previous_separator_position < last_array_index) {
6907 String::WriteToFlat<Char>(separator, &buffer[cursor],
6908 0, separator_length);
6909 cursor += separator_length;
6910 previous_separator_position++;
6911 }
6912 }
6913 ASSERT(cursor <= buffer.length());
6914}
6915
6916
6917RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6918 NoHandleAllocation ha;
6919 ASSERT(args.length() == 3);
6920 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006921 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6922 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006923 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6924 CONVERT_CHECKED(String, separator, args[2]);
6925 // elements_array is fast-mode JSarray of alternating positions
6926 // (increasing order) and strings.
6927 // array_length is length of original array (used to add separators);
6928 // separator is string to put between elements. Assumed to be non-empty.
6929
6930 // Find total length of join result.
6931 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006932 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006933 int max_string_length;
6934 if (is_ascii) {
6935 max_string_length = SeqAsciiString::kMaxLength;
6936 } else {
6937 max_string_length = SeqTwoByteString::kMaxLength;
6938 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006939 bool overflow = false;
6940 CONVERT_NUMBER_CHECKED(int, elements_length,
6941 Int32, elements_array->length());
6942 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6943 FixedArray* elements = FixedArray::cast(elements_array->elements());
6944 for (int i = 0; i < elements_length; i += 2) {
6945 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6946 CONVERT_CHECKED(String, string, elements->get(i + 1));
6947 int length = string->length();
6948 if (is_ascii && !string->IsAsciiRepresentation()) {
6949 is_ascii = false;
6950 max_string_length = SeqTwoByteString::kMaxLength;
6951 }
6952 if (length > max_string_length ||
6953 max_string_length - length < string_length) {
6954 overflow = true;
6955 break;
6956 }
6957 string_length += length;
6958 }
6959 int separator_length = separator->length();
6960 if (!overflow && separator_length > 0) {
6961 if (array_length <= 0x7fffffffu) {
6962 int separator_count = static_cast<int>(array_length) - 1;
6963 int remaining_length = max_string_length - string_length;
6964 if ((remaining_length / separator_length) >= separator_count) {
6965 string_length += separator_length * (array_length - 1);
6966 } else {
6967 // Not room for the separators within the maximal string length.
6968 overflow = true;
6969 }
6970 } else {
6971 // Nonempty separator and at least 2^31-1 separators necessary
6972 // means that the string is too large to create.
6973 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6974 overflow = true;
6975 }
6976 }
6977 if (overflow) {
6978 // Throw OutOfMemory exception for creating too large a string.
6979 V8::FatalProcessOutOfMemory("Array join result too large.");
6980 }
6981
6982 if (is_ascii) {
6983 MaybeObject* result_allocation =
6984 isolate->heap()->AllocateRawAsciiString(string_length);
6985 if (result_allocation->IsFailure()) return result_allocation;
6986 SeqAsciiString* result_string =
6987 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6988 JoinSparseArrayWithSeparator<char>(elements,
6989 elements_length,
6990 array_length,
6991 separator,
6992 Vector<char>(result_string->GetChars(),
6993 string_length));
6994 return result_string;
6995 } else {
6996 MaybeObject* result_allocation =
6997 isolate->heap()->AllocateRawTwoByteString(string_length);
6998 if (result_allocation->IsFailure()) return result_allocation;
6999 SeqTwoByteString* result_string =
7000 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7001 JoinSparseArrayWithSeparator<uc16>(elements,
7002 elements_length,
7003 array_length,
7004 separator,
7005 Vector<uc16>(result_string->GetChars(),
7006 string_length));
7007 return result_string;
7008 }
7009}
7010
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007011
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007012RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007013 NoHandleAllocation ha;
7014 ASSERT(args.length() == 2);
7015
7016 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7017 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007018 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007019}
7020
7021
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007022RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007023 NoHandleAllocation ha;
7024 ASSERT(args.length() == 2);
7025
7026 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7027 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007028 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007029}
7030
7031
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007032RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007033 NoHandleAllocation ha;
7034 ASSERT(args.length() == 2);
7035
7036 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7037 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007038 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007039}
7040
7041
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007042RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007043 NoHandleAllocation ha;
7044 ASSERT(args.length() == 1);
7045
7046 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007047 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007048}
7049
7050
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007051RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007052 NoHandleAllocation ha;
7053 ASSERT(args.length() == 2);
7054
7055 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7056 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007057 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007058}
7059
7060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007061RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007062 NoHandleAllocation ha;
7063 ASSERT(args.length() == 2);
7064
7065 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7066 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007067 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068}
7069
7070
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007071RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007072 NoHandleAllocation ha;
7073 ASSERT(args.length() == 2);
7074
7075 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7076 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007077 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007078}
7079
7080
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007081RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007082 NoHandleAllocation ha;
7083 ASSERT(args.length() == 2);
7084
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007085 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7086 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007087 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7088 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7089 if (x == y) return Smi::FromInt(EQUAL);
7090 Object* result;
7091 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7092 result = Smi::FromInt(EQUAL);
7093 } else {
7094 result = Smi::FromInt(NOT_EQUAL);
7095 }
7096 return result;
7097}
7098
7099
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007100RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007101 NoHandleAllocation ha;
7102 ASSERT(args.length() == 2);
7103
7104 CONVERT_CHECKED(String, x, args[0]);
7105 CONVERT_CHECKED(String, y, args[1]);
7106
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007107 bool not_equal = !x->Equals(y);
7108 // This is slightly convoluted because the value that signifies
7109 // equality is 0 and inequality is 1 so we have to negate the result
7110 // from String::Equals.
7111 ASSERT(not_equal == 0 || not_equal == 1);
7112 STATIC_CHECK(EQUAL == 0);
7113 STATIC_CHECK(NOT_EQUAL == 1);
7114 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007115}
7116
7117
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007118RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007119 NoHandleAllocation ha;
7120 ASSERT(args.length() == 3);
7121
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007122 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7123 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007124 if (isnan(x) || isnan(y)) return args[2];
7125 if (x == y) return Smi::FromInt(EQUAL);
7126 if (isless(x, y)) return Smi::FromInt(LESS);
7127 return Smi::FromInt(GREATER);
7128}
7129
7130
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007131// Compare two Smis as if they were converted to strings and then
7132// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007133RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007134 NoHandleAllocation ha;
7135 ASSERT(args.length() == 2);
7136
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007137 // Extract the integer values from the Smis.
7138 CONVERT_CHECKED(Smi, x, args[0]);
7139 CONVERT_CHECKED(Smi, y, args[1]);
7140 int x_value = x->value();
7141 int y_value = y->value();
7142
7143 // If the integers are equal so are the string representations.
7144 if (x_value == y_value) return Smi::FromInt(EQUAL);
7145
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007146 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007147 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007148 if (x_value == 0 || y_value == 0)
7149 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007150
ager@chromium.org32912102009-01-16 10:38:43 +00007151 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007152 // smallest because the char code of '-' is less than the char code
7153 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007154
7155 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7156 // architectures using 32-bit Smis.
7157 uint32_t x_scaled = x_value;
7158 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007159 if (x_value < 0 || y_value < 0) {
7160 if (y_value >= 0) return Smi::FromInt(LESS);
7161 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007162 x_scaled = -x_value;
7163 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007164 }
7165
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007166 static const uint32_t kPowersOf10[] = {
7167 1, 10, 100, 1000, 10*1000, 100*1000,
7168 1000*1000, 10*1000*1000, 100*1000*1000,
7169 1000*1000*1000
7170 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007171
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007172 // If the integers have the same number of decimal digits they can be
7173 // compared directly as the numeric order is the same as the
7174 // lexicographic order. If one integer has fewer digits, it is scaled
7175 // by some power of 10 to have the same number of digits as the longer
7176 // integer. If the scaled integers are equal it means the shorter
7177 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007178
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007179 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7180 int x_log2 = IntegerLog2(x_scaled);
7181 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7182 x_log10 -= x_scaled < kPowersOf10[x_log10];
7183
7184 int y_log2 = IntegerLog2(y_scaled);
7185 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7186 y_log10 -= y_scaled < kPowersOf10[y_log10];
7187
7188 int tie = EQUAL;
7189
7190 if (x_log10 < y_log10) {
7191 // X has fewer digits. We would like to simply scale up X but that
7192 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7193 // be scaled up to 9_000_000_000. So we scale up by the next
7194 // smallest power and scale down Y to drop one digit. It is OK to
7195 // drop one digit from the longer integer since the final digit is
7196 // past the length of the shorter integer.
7197 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7198 y_scaled /= 10;
7199 tie = LESS;
7200 } else if (y_log10 < x_log10) {
7201 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7202 x_scaled /= 10;
7203 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007204 }
7205
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007206 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7207 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7208 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007209}
7210
7211
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007212static Object* StringInputBufferCompare(RuntimeState* state,
7213 String* x,
7214 String* y) {
7215 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7216 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007217 bufx.Reset(x);
7218 bufy.Reset(y);
7219 while (bufx.has_more() && bufy.has_more()) {
7220 int d = bufx.GetNext() - bufy.GetNext();
7221 if (d < 0) return Smi::FromInt(LESS);
7222 else if (d > 0) return Smi::FromInt(GREATER);
7223 }
7224
7225 // x is (non-trivial) prefix of y:
7226 if (bufy.has_more()) return Smi::FromInt(LESS);
7227 // y is prefix of x:
7228 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7229}
7230
7231
7232static Object* FlatStringCompare(String* x, String* y) {
7233 ASSERT(x->IsFlat());
7234 ASSERT(y->IsFlat());
7235 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7236 int prefix_length = x->length();
7237 if (y->length() < prefix_length) {
7238 prefix_length = y->length();
7239 equal_prefix_result = Smi::FromInt(GREATER);
7240 } else if (y->length() > prefix_length) {
7241 equal_prefix_result = Smi::FromInt(LESS);
7242 }
7243 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007244 String::FlatContent x_content = x->GetFlatContent();
7245 String::FlatContent y_content = y->GetFlatContent();
7246 if (x_content.IsAscii()) {
7247 Vector<const char> x_chars = x_content.ToAsciiVector();
7248 if (y_content.IsAscii()) {
7249 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007250 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007251 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007252 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007253 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7254 }
7255 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007256 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7257 if (y_content.IsAscii()) {
7258 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007259 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7260 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007261 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007262 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7263 }
7264 }
7265 Object* result;
7266 if (r == 0) {
7267 result = equal_prefix_result;
7268 } else {
7269 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7270 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007271 ASSERT(result ==
7272 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007273 return result;
7274}
7275
7276
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007277RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007278 NoHandleAllocation ha;
7279 ASSERT(args.length() == 2);
7280
7281 CONVERT_CHECKED(String, x, args[0]);
7282 CONVERT_CHECKED(String, y, args[1]);
7283
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007284 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007285
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007286 // A few fast case tests before we flatten.
7287 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007288 if (y->length() == 0) {
7289 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007290 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007291 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007292 return Smi::FromInt(LESS);
7293 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007294
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007295 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007296 if (d < 0) return Smi::FromInt(LESS);
7297 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007298
lrn@chromium.org303ada72010-10-27 09:33:13 +00007299 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007300 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007301 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7302 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007303 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007304 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7305 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007306
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007307 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007308 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007309}
7310
7311
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007312RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007313 NoHandleAllocation ha;
7314 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007315 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007316
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007317 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007318 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007319}
7320
7321
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007322RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007323 NoHandleAllocation ha;
7324 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007325 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007326
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007327 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007328 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007329}
7330
7331
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007332RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007333 NoHandleAllocation ha;
7334 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007335 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007336
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007337 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007338 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007339}
7340
7341
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007342static const double kPiDividedBy4 = 0.78539816339744830962;
7343
7344
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007345RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007346 NoHandleAllocation ha;
7347 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007348 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007349
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007350 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7351 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007352 double result;
7353 if (isinf(x) && isinf(y)) {
7354 // Make sure that the result in case of two infinite arguments
7355 // is a multiple of Pi / 4. The sign of the result is determined
7356 // by the first argument (x) and the sign of the second argument
7357 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007358 int multiplier = (x < 0) ? -1 : 1;
7359 if (y < 0) multiplier *= 3;
7360 result = multiplier * kPiDividedBy4;
7361 } else {
7362 result = atan2(x, y);
7363 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007364 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007365}
7366
7367
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007368RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007369 NoHandleAllocation ha;
7370 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007371 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007372
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007373 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007374 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007375}
7376
7377
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007378RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007379 NoHandleAllocation ha;
7380 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007381 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007382
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007383 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007384 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007385}
7386
7387
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007388RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007389 NoHandleAllocation ha;
7390 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007391 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007392
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007393 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007394 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007395}
7396
7397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007398RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007399 NoHandleAllocation ha;
7400 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007401 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007402
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007403 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007404 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007405}
7406
7407
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007408RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007409 NoHandleAllocation ha;
7410 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007411 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007412
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007413 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007414 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007415}
7416
7417
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007418RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007419 NoHandleAllocation ha;
7420 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007421 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007422
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007423 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007424
7425 // If the second argument is a smi, it is much faster to call the
7426 // custom powi() function than the generic pow().
7427 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007428 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007429 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007430 }
7431
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007432 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007433 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007434}
7435
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007436// Fast version of Math.pow if we know that y is not an integer and
7437// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007438RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007439 NoHandleAllocation ha;
7440 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007441 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7442 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007443 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007444 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007445 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007446 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007447 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007448 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007449 }
7450}
7451
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007452
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007453RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007454 NoHandleAllocation ha;
7455 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007456 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007457
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007458 if (!args[0]->IsHeapNumber()) {
7459 // Must be smi. Return the argument unchanged for all the other types
7460 // to make fuzz-natives test happy.
7461 return args[0];
7462 }
7463
7464 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7465
7466 double value = number->value();
7467 int exponent = number->get_exponent();
7468 int sign = number->get_sign();
7469
danno@chromium.org160a7b02011-04-18 15:51:38 +00007470 if (exponent < -1) {
7471 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7472 if (sign) return isolate->heap()->minus_zero_value();
7473 return Smi::FromInt(0);
7474 }
7475
7476 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7477 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7478 // agument holds for 32-bit smis).
7479 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007480 return Smi::FromInt(static_cast<int>(value + 0.5));
7481 }
7482
7483 // If the magnitude is big enough, there's no place for fraction part. If we
7484 // try to add 0.5 to this number, 1.0 will be added instead.
7485 if (exponent >= 52) {
7486 return number;
7487 }
7488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007489 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007490
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007491 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007492 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007493}
7494
7495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007496RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007497 NoHandleAllocation ha;
7498 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007499 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007500
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007501 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007502 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007503}
7504
7505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007506RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007507 NoHandleAllocation ha;
7508 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007509 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007510
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007511 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007512 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007513}
7514
7515
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007516RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007517 NoHandleAllocation ha;
7518 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007519 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007520
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007521 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007522 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007523}
7524
7525
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007526static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007527 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7528 181, 212, 243, 273, 304, 334};
7529 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7530 182, 213, 244, 274, 305, 335};
7531
7532 year += month / 12;
7533 month %= 12;
7534 if (month < 0) {
7535 year--;
7536 month += 12;
7537 }
7538
7539 ASSERT(month >= 0);
7540 ASSERT(month < 12);
7541
7542 // year_delta is an arbitrary number such that:
7543 // a) year_delta = -1 (mod 400)
7544 // b) year + year_delta > 0 for years in the range defined by
7545 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7546 // Jan 1 1970. This is required so that we don't run into integer
7547 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007548 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007549 // operations.
7550 static const int year_delta = 399999;
7551 static const int base_day = 365 * (1970 + year_delta) +
7552 (1970 + year_delta) / 4 -
7553 (1970 + year_delta) / 100 +
7554 (1970 + year_delta) / 400;
7555
7556 int year1 = year + year_delta;
7557 int day_from_year = 365 * year1 +
7558 year1 / 4 -
7559 year1 / 100 +
7560 year1 / 400 -
7561 base_day;
7562
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007563 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7564 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007565 }
7566
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007567 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007568}
7569
7570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007571RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007572 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007573 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007574
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007575 CONVERT_SMI_ARG_CHECKED(year, 0);
7576 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007577
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007578 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007579}
7580
7581
7582static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7583static const int kDaysIn4Years = 4 * 365 + 1;
7584static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7585static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7586static const int kDays1970to2000 = 30 * 365 + 7;
7587static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7588 kDays1970to2000;
7589static const int kYearsOffset = 400000;
7590
7591static const char kDayInYear[] = {
7592 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7593 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7594 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7595 22, 23, 24, 25, 26, 27, 28,
7596 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7597 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7598 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7599 22, 23, 24, 25, 26, 27, 28, 29, 30,
7600 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7601 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7602 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7603 22, 23, 24, 25, 26, 27, 28, 29, 30,
7604 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7605 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7606 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7607 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7608 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7609 22, 23, 24, 25, 26, 27, 28, 29, 30,
7610 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7611 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7612 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7613 22, 23, 24, 25, 26, 27, 28, 29, 30,
7614 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7615 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7616
7617 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7618 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7619 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7620 22, 23, 24, 25, 26, 27, 28,
7621 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7622 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7623 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7624 22, 23, 24, 25, 26, 27, 28, 29, 30,
7625 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7626 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7627 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7628 22, 23, 24, 25, 26, 27, 28, 29, 30,
7629 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7630 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7631 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7632 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7633 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7634 22, 23, 24, 25, 26, 27, 28, 29, 30,
7635 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7636 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7637 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7638 22, 23, 24, 25, 26, 27, 28, 29, 30,
7639 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7640 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7641
7642 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7643 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7644 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7645 22, 23, 24, 25, 26, 27, 28, 29,
7646 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7647 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7648 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7649 22, 23, 24, 25, 26, 27, 28, 29, 30,
7650 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7651 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7652 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7653 22, 23, 24, 25, 26, 27, 28, 29, 30,
7654 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7655 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7656 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7657 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7658 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7659 22, 23, 24, 25, 26, 27, 28, 29, 30,
7660 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7661 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7662 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7663 22, 23, 24, 25, 26, 27, 28, 29, 30,
7664 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7665 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7666
7667 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7668 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7669 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7670 22, 23, 24, 25, 26, 27, 28,
7671 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7672 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7673 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7674 22, 23, 24, 25, 26, 27, 28, 29, 30,
7675 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7676 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7677 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7678 22, 23, 24, 25, 26, 27, 28, 29, 30,
7679 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7680 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7681 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7682 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7683 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7684 22, 23, 24, 25, 26, 27, 28, 29, 30,
7685 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7686 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7687 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7688 22, 23, 24, 25, 26, 27, 28, 29, 30,
7689 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7690 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7691
7692static const char kMonthInYear[] = {
7693 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7694 0, 0, 0, 0, 0, 0,
7695 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7696 1, 1, 1,
7697 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7698 2, 2, 2, 2, 2, 2,
7699 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7700 3, 3, 3, 3, 3,
7701 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7702 4, 4, 4, 4, 4, 4,
7703 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7704 5, 5, 5, 5, 5,
7705 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7706 6, 6, 6, 6, 6, 6,
7707 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7708 7, 7, 7, 7, 7, 7,
7709 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7710 8, 8, 8, 8, 8,
7711 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7712 9, 9, 9, 9, 9, 9,
7713 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7714 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7715 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7716 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7717
7718 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7719 0, 0, 0, 0, 0, 0,
7720 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7721 1, 1, 1,
7722 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7723 2, 2, 2, 2, 2, 2,
7724 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7725 3, 3, 3, 3, 3,
7726 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7727 4, 4, 4, 4, 4, 4,
7728 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7729 5, 5, 5, 5, 5,
7730 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7731 6, 6, 6, 6, 6, 6,
7732 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7733 7, 7, 7, 7, 7, 7,
7734 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7735 8, 8, 8, 8, 8,
7736 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7737 9, 9, 9, 9, 9, 9,
7738 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7739 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7740 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7741 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7742
7743 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7744 0, 0, 0, 0, 0, 0,
7745 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7746 1, 1, 1, 1,
7747 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7748 2, 2, 2, 2, 2, 2,
7749 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7750 3, 3, 3, 3, 3,
7751 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7752 4, 4, 4, 4, 4, 4,
7753 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7754 5, 5, 5, 5, 5,
7755 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7756 6, 6, 6, 6, 6, 6,
7757 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7758 7, 7, 7, 7, 7, 7,
7759 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7760 8, 8, 8, 8, 8,
7761 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7762 9, 9, 9, 9, 9, 9,
7763 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7764 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7765 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7766 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7767
7768 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7769 0, 0, 0, 0, 0, 0,
7770 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7771 1, 1, 1,
7772 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7773 2, 2, 2, 2, 2, 2,
7774 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7775 3, 3, 3, 3, 3,
7776 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7777 4, 4, 4, 4, 4, 4,
7778 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7779 5, 5, 5, 5, 5,
7780 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7781 6, 6, 6, 6, 6, 6,
7782 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7783 7, 7, 7, 7, 7, 7,
7784 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7785 8, 8, 8, 8, 8,
7786 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7787 9, 9, 9, 9, 9, 9,
7788 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7789 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7790 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7791 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7792
7793
7794// This function works for dates from 1970 to 2099.
7795static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007796 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007797#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007798 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007799#endif
7800
7801 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7802 date %= kDaysIn4Years;
7803
7804 month = kMonthInYear[date];
7805 day = kDayInYear[date];
7806
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007807 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007808}
7809
7810
7811static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007812 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007813#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007814 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007815#endif
7816
7817 date += kDaysOffset;
7818 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7819 date %= kDaysIn400Years;
7820
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007821 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007822
7823 date--;
7824 int yd1 = date / kDaysIn100Years;
7825 date %= kDaysIn100Years;
7826 year += 100 * yd1;
7827
7828 date++;
7829 int yd2 = date / kDaysIn4Years;
7830 date %= kDaysIn4Years;
7831 year += 4 * yd2;
7832
7833 date--;
7834 int yd3 = date / 365;
7835 date %= 365;
7836 year += yd3;
7837
7838 bool is_leap = (!yd1 || yd2) && !yd3;
7839
7840 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007841 ASSERT(is_leap || (date >= 0));
7842 ASSERT((date < 365) || (is_leap && (date < 366)));
7843 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007844 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7845 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007846
7847 if (is_leap) {
7848 day = kDayInYear[2*365 + 1 + date];
7849 month = kMonthInYear[2*365 + 1 + date];
7850 } else {
7851 day = kDayInYear[date];
7852 month = kMonthInYear[date];
7853 }
7854
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007855 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007856}
7857
7858
7859static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007860 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007861 if (date >= 0 && date < 32 * kDaysIn4Years) {
7862 DateYMDFromTimeAfter1970(date, year, month, day);
7863 } else {
7864 DateYMDFromTimeSlow(date, year, month, day);
7865 }
7866}
7867
7868
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007869RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007870 NoHandleAllocation ha;
7871 ASSERT(args.length() == 2);
7872
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007873 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007874 CONVERT_CHECKED(JSArray, res_array, args[1]);
7875
7876 int year, month, day;
7877 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7878
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007879 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7880 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007881 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007882
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007883 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7884 if (maybe->IsFailure()) return maybe;
7885 FixedArray* elms = FixedArray::cast(res_array->elements());
7886 elms->set(0, Smi::FromInt(year));
7887 elms->set(1, Smi::FromInt(month));
7888 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007889
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007890 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007891}
7892
7893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007894RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007895 HandleScope scope(isolate);
7896 ASSERT(args.length() == 3);
7897
7898 Handle<JSFunction> callee = args.at<JSFunction>(0);
7899 Object** parameters = reinterpret_cast<Object**>(args[1]);
7900 const int argument_count = Smi::cast(args[2])->value();
7901
7902 Handle<JSObject> result =
7903 isolate->factory()->NewArgumentsObject(callee, argument_count);
7904 // Allocate the elements if needed.
7905 int parameter_count = callee->shared()->formal_parameter_count();
7906 if (argument_count > 0) {
7907 if (parameter_count > 0) {
7908 int mapped_count = Min(argument_count, parameter_count);
7909 Handle<FixedArray> parameter_map =
7910 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7911 parameter_map->set_map(
7912 isolate->heap()->non_strict_arguments_elements_map());
7913
7914 Handle<Map> old_map(result->map());
7915 Handle<Map> new_map =
7916 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007917 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007918
7919 result->set_map(*new_map);
7920 result->set_elements(*parameter_map);
7921
7922 // Store the context and the arguments array at the beginning of the
7923 // parameter map.
7924 Handle<Context> context(isolate->context());
7925 Handle<FixedArray> arguments =
7926 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7927 parameter_map->set(0, *context);
7928 parameter_map->set(1, *arguments);
7929
7930 // Loop over the actual parameters backwards.
7931 int index = argument_count - 1;
7932 while (index >= mapped_count) {
7933 // These go directly in the arguments array and have no
7934 // corresponding slot in the parameter map.
7935 arguments->set(index, *(parameters - index - 1));
7936 --index;
7937 }
7938
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007939 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007940 while (index >= 0) {
7941 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007942 Handle<String> name(scope_info->ParameterName(index));
7943 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007944 bool duplicate = false;
7945 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007946 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007947 duplicate = true;
7948 break;
7949 }
7950 }
7951
7952 if (duplicate) {
7953 // This goes directly in the arguments array with a hole in the
7954 // parameter map.
7955 arguments->set(index, *(parameters - index - 1));
7956 parameter_map->set_the_hole(index + 2);
7957 } else {
7958 // The context index goes in the parameter map with a hole in the
7959 // arguments array.
7960 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007961 for (int j = 0; j < context_local_count; ++j) {
7962 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007963 context_index = j;
7964 break;
7965 }
7966 }
7967 ASSERT(context_index >= 0);
7968 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007969 parameter_map->set(index + 2, Smi::FromInt(
7970 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007971 }
7972
7973 --index;
7974 }
7975 } else {
7976 // If there is no aliasing, the arguments object elements are not
7977 // special in any way.
7978 Handle<FixedArray> elements =
7979 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7980 result->set_elements(*elements);
7981 for (int i = 0; i < argument_count; ++i) {
7982 elements->set(i, *(parameters - i - 1));
7983 }
7984 }
7985 }
7986 return *result;
7987}
7988
7989
7990RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007991 NoHandleAllocation ha;
7992 ASSERT(args.length() == 3);
7993
7994 JSFunction* callee = JSFunction::cast(args[0]);
7995 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007996 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007997
lrn@chromium.org303ada72010-10-27 09:33:13 +00007998 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007999 { MaybeObject* maybe_result =
8000 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008001 if (!maybe_result->ToObject(&result)) return maybe_result;
8002 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008003 // Allocate the elements if needed.
8004 if (length > 0) {
8005 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008006 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008007 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008008 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8009 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008010
8011 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008012 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008013 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008014 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008015
8016 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008017 for (int i = 0; i < length; i++) {
8018 array->set(i, *--parameters, mode);
8019 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008020 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008021 }
8022 return result;
8023}
8024
8025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008026RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008027 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008028 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00008029 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008030 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008031 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008032
whesse@chromium.org7b260152011-06-20 15:33:18 +00008033 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008034 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008035 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008036 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008037 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8038 context,
8039 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008040 return *result;
8041}
8042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008043
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008044// Find the arguments of the JavaScript function invocation that called
8045// into C++ code. Collect these in a newly allocated array of handles (possibly
8046// prefixed by a number of empty handles).
8047static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8048 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008049 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008050 // Find frame containing arguments passed to the caller.
8051 JavaScriptFrameIterator it;
8052 JavaScriptFrame* frame = it.frame();
8053 List<JSFunction*> functions(2);
8054 frame->GetFunctions(&functions);
8055 if (functions.length() > 1) {
8056 int inlined_frame_index = functions.length() - 1;
8057 JSFunction* inlined_function = functions[inlined_frame_index];
8058 int args_count = inlined_function->shared()->formal_parameter_count();
8059 ScopedVector<SlotRef> args_slots(args_count);
8060 SlotRef::ComputeSlotMappingForArguments(frame,
8061 inlined_frame_index,
8062 &args_slots);
8063
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008064 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008065 SmartArrayPointer<Handle<Object> > param_data(
8066 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008067 for (int i = 0; i < args_count; i++) {
8068 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008069 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008070 }
8071 return param_data;
8072 } else {
8073 it.AdvanceToArgumentsFrame();
8074 frame = it.frame();
8075 int args_count = frame->ComputeParametersCount();
8076
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008077 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008078 SmartArrayPointer<Handle<Object> > param_data(
8079 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008080 for (int i = 0; i < args_count; i++) {
8081 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008082 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008083 }
8084 return param_data;
8085 }
8086}
8087
8088
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008089RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8090 HandleScope scope(isolate);
8091 ASSERT(args.length() == 4);
8092 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8093 RUNTIME_ASSERT(args[3]->IsNumber());
8094 Handle<Object> bindee = args.at<Object>(1);
8095
8096 // TODO(lrn): Create bound function in C++ code from premade shared info.
8097 bound_function->shared()->set_bound(true);
8098 // Get all arguments of calling function (Function.prototype.bind).
8099 int argc = 0;
8100 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8101 // Don't count the this-arg.
8102 if (argc > 0) {
8103 ASSERT(*arguments[0] == args[2]);
8104 argc--;
8105 } else {
8106 ASSERT(args[2]->IsUndefined());
8107 }
8108 // Initialize array of bindings (function, this, and any existing arguments
8109 // if the function was already bound).
8110 Handle<FixedArray> new_bindings;
8111 int i;
8112 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8113 Handle<FixedArray> old_bindings(
8114 JSFunction::cast(*bindee)->function_bindings());
8115 new_bindings =
8116 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8117 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8118 i = 0;
8119 for (int n = old_bindings->length(); i < n; i++) {
8120 new_bindings->set(i, old_bindings->get(i));
8121 }
8122 } else {
8123 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8124 new_bindings = isolate->factory()->NewFixedArray(array_size);
8125 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8126 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8127 i = 2;
8128 }
8129 // Copy arguments, skipping the first which is "this_arg".
8130 for (int j = 0; j < argc; j++, i++) {
8131 new_bindings->set(i, *arguments[j + 1]);
8132 }
8133 new_bindings->set_map(isolate->heap()->fixed_cow_array_map());
8134 bound_function->set_function_bindings(*new_bindings);
8135
8136 // Update length.
8137 Handle<String> length_symbol = isolate->factory()->length_symbol();
8138 Handle<Object> new_length(args.at<Object>(3));
8139 PropertyAttributes attr =
8140 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8141 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8142 return *bound_function;
8143}
8144
8145
8146RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8147 HandleScope handles(isolate);
8148 ASSERT(args.length() == 1);
danno@chromium.org2c456792011-11-11 12:00:53 +00008149 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008150 if (callable->IsJSFunction()) {
8151 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8152 if (function->shared()->bound()) {
8153 Handle<FixedArray> bindings(function->function_bindings());
8154 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8155 return *isolate->factory()->NewJSArrayWithElements(bindings);
8156 }
8157 }
8158 return isolate->heap()->undefined_value();
8159}
8160
8161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008162RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008163 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008164 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008165 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008166 CONVERT_ARG_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008167 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008168
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008169 // The argument is a bound function. Extract its bound arguments
8170 // and callable.
8171 Handle<FixedArray> bound_args =
8172 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8173 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8174 Handle<Object> bound_function(
8175 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8176 ASSERT(!bound_function->IsJSFunction() ||
8177 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008178
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008179 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008180 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008181 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008182 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008183 param_data[i] = Handle<Object>(bound_args->get(
8184 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008185 }
8186
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008187 if (!bound_function->IsJSFunction()) {
8188 bool exception_thrown;
8189 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8190 &exception_thrown);
8191 if (exception_thrown) return Failure::Exception();
8192 }
8193 ASSERT(bound_function->IsJSFunction());
8194
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008195 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008196 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008197 Execution::New(Handle<JSFunction>::cast(bound_function),
8198 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008199 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008200 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008201 }
8202 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008203 return *result;
8204}
8205
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008206
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008207static void TrySettingInlineConstructStub(Isolate* isolate,
8208 Handle<JSFunction> function) {
8209 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008210 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008211 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008212 }
8213 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008214 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008215 Handle<Code> code = compiler.CompileConstructStub(function);
8216 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008217 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008218}
8219
8220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008221RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008222 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008223 ASSERT(args.length() == 1);
8224
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008225 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008226
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008227 // If the constructor isn't a proper function we throw a type error.
8228 if (!constructor->IsJSFunction()) {
8229 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8230 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008231 isolate->factory()->NewTypeError("not_constructor", arguments);
8232 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008233 }
8234
8235 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008236
8237 // If function should not have prototype, construction is not allowed. In this
8238 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008239 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008240 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8241 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008242 isolate->factory()->NewTypeError("not_constructor", arguments);
8243 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008244 }
8245
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008246#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008247 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008248 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008249 if (debug->StepInActive()) {
8250 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008251 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008252#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008253
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008254 if (function->has_initial_map()) {
8255 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008256 // The 'Function' function ignores the receiver object when
8257 // called using 'new' and creates a new JSFunction object that
8258 // is returned. The receiver object is only used for error
8259 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008260 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008261 // allocate JSFunctions since it does not properly initialize
8262 // the shared part of the function. Since the receiver is
8263 // ignored anyway, we use the global object as the receiver
8264 // instead of a new JSFunction object. This way, errors are
8265 // reported the same way whether or not 'Function' is called
8266 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008267 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008268 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008269 }
8270
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008271 // The function should be compiled for the optimization hints to be
8272 // available. We cannot use EnsureCompiled because that forces a
8273 // compilation through the shared function info which makes it
8274 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008275 if (!function->is_compiled()) {
8276 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8277 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008278
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008279 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008280 if (!function->has_initial_map() &&
8281 shared->IsInobjectSlackTrackingInProgress()) {
8282 // The tracking is already in progress for another function. We can only
8283 // track one initial_map at a time, so we force the completion before the
8284 // function is called as a constructor for the first time.
8285 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008286 }
8287
8288 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008289 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8290 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008291 // Delay setting the stub if inobject slack tracking is in progress.
8292 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008293 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008294 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008295
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008296 isolate->counters()->constructed_objects()->Increment();
8297 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008298
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008299 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008300}
8301
8302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008303RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008304 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008305 ASSERT(args.length() == 1);
8306
8307 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8308 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008309 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008311 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008312}
8313
8314
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008315RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008316 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008317 ASSERT(args.length() == 1);
8318
8319 Handle<JSFunction> function = args.at<JSFunction>(0);
8320#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008321 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008322 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008323 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008324 PrintF("]\n");
8325 }
8326#endif
8327
lrn@chromium.org34e60782011-09-15 07:25:40 +00008328 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008329 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008330 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008331 return Failure::Exception();
8332 }
8333
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008334 // All done. Return the compiled code.
8335 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008336 return function->code();
8337}
8338
8339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008340RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008341 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008342 ASSERT(args.length() == 1);
8343 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008344
8345 // If the function is not compiled ignore the lazy
8346 // recompilation. This can happen if the debugger is activated and
8347 // the function is returned to the not compiled state.
8348 if (!function->shared()->is_compiled()) {
8349 function->ReplaceCode(function->shared()->code());
8350 return function->code();
8351 }
8352
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008353 // If the function is not optimizable or debugger is active continue using the
8354 // code from the full compiler.
8355 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008356 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008357 if (FLAG_trace_opt) {
8358 PrintF("[failed to optimize ");
8359 function->PrintName();
8360 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8361 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008362 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008363 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008364 function->ReplaceCode(function->shared()->code());
8365 return function->code();
8366 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008367 if (JSFunction::CompileOptimized(function,
8368 AstNode::kNoNumber,
8369 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008370 return function->code();
8371 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008372 if (FLAG_trace_opt) {
8373 PrintF("[failed to optimize ");
8374 function->PrintName();
8375 PrintF(": optimized compilation failed]\n");
8376 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008377 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008378 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008379}
8380
8381
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008382class ActivationsFinder : public ThreadVisitor {
8383 public:
8384 explicit ActivationsFinder(JSFunction* function)
8385 : function_(function), has_activations_(false) {}
8386
8387 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8388 if (has_activations_) return;
8389
8390 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8391 JavaScriptFrame* frame = it.frame();
8392 if (frame->is_optimized() && frame->function() == function_) {
8393 has_activations_ = true;
8394 return;
8395 }
8396 }
8397 }
8398
8399 bool has_activations() { return has_activations_; }
8400
8401 private:
8402 JSFunction* function_;
8403 bool has_activations_;
8404};
8405
8406
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008407RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008408 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008409 ASSERT(args.length() == 1);
8410 RUNTIME_ASSERT(args[0]->IsSmi());
8411 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008412 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008413 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8414 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008415 int frames = deoptimizer->output_count();
8416
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008417 deoptimizer->MaterializeHeapNumbers();
8418 delete deoptimizer;
8419
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008420 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008421 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008422 for (int i = 0; i < frames - 1; i++) it.Advance();
8423 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008424
8425 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008426 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008427 Handle<Object> arguments;
8428 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008429 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008430 if (arguments.is_null()) {
8431 // FunctionGetArguments can't throw an exception, so cast away the
8432 // doubt with an assert.
8433 arguments = Handle<Object>(
8434 Accessors::FunctionGetArguments(*function,
8435 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008436 ASSERT(*arguments != isolate->heap()->null_value());
8437 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008438 }
8439 frame->SetExpression(i, *arguments);
8440 }
8441 }
8442
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008443 if (type == Deoptimizer::EAGER) {
8444 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008445 }
8446
8447 // Avoid doing too much work when running with --always-opt and keep
8448 // the optimized code around.
8449 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008450 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008451 }
8452
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008453 // Find other optimized activations of the function.
8454 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008455 while (!it.done()) {
8456 JavaScriptFrame* frame = it.frame();
8457 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008458 has_other_activations = true;
8459 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008460 }
8461 it.Advance();
8462 }
8463
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008464 if (!has_other_activations) {
8465 ActivationsFinder activations_finder(*function);
8466 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8467 has_other_activations = activations_finder.has_activations();
8468 }
8469
8470 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008471 if (FLAG_trace_deopt) {
8472 PrintF("[removing optimized code for: ");
8473 function->PrintName();
8474 PrintF("]\n");
8475 }
8476 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008477 } else {
8478 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008479 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008480 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008481}
8482
8483
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008484RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008485 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008486 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008487 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008488}
8489
8490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008491RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008492 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008493 ASSERT(args.length() == 1);
8494 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008495 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008496
8497 Deoptimizer::DeoptimizeFunction(*function);
8498
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008499 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008500}
8501
8502
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008503RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8504#if defined(USE_SIMULATOR)
8505 return isolate->heap()->true_value();
8506#else
8507 return isolate->heap()->false_value();
8508#endif
8509}
8510
8511
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008512RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8513 HandleScope scope(isolate);
8514 ASSERT(args.length() == 1);
8515 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8516 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8517 function->MarkForLazyRecompilation();
8518 return isolate->heap()->undefined_value();
8519}
8520
8521
lrn@chromium.org1c092762011-05-09 09:42:16 +00008522RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8523 HandleScope scope(isolate);
8524 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008525 // The least significant bit (after untagging) indicates whether the
8526 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008527 if (!V8::UseCrankshaft()) {
8528 return Smi::FromInt(4); // 4 == "never".
8529 }
8530 if (FLAG_always_opt) {
8531 return Smi::FromInt(3); // 3 == "always".
8532 }
8533 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8534 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8535 : Smi::FromInt(2); // 2 == "no".
8536}
8537
8538
8539RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8540 HandleScope scope(isolate);
8541 ASSERT(args.length() == 1);
8542 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8543 return Smi::FromInt(function->shared()->opt_count());
8544}
8545
8546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008547RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008548 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008549 ASSERT(args.length() == 1);
8550 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8551
8552 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008553 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008554
8555 // We have hit a back edge in an unoptimized frame for a function that was
8556 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008557 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008558 // Keep track of whether we've succeeded in optimizing.
8559 bool succeeded = unoptimized->optimizable();
8560 if (succeeded) {
8561 // If we are trying to do OSR when there are already optimized
8562 // activations of the function, it means (a) the function is directly or
8563 // indirectly recursive and (b) an optimized invocation has been
8564 // deoptimized so that we are currently in an unoptimized activation.
8565 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008566 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008567 while (succeeded && !it.done()) {
8568 JavaScriptFrame* frame = it.frame();
8569 succeeded = !frame->is_optimized() || frame->function() != *function;
8570 it.Advance();
8571 }
8572 }
8573
8574 int ast_id = AstNode::kNoNumber;
8575 if (succeeded) {
8576 // The top JS function is this one, the PC is somewhere in the
8577 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008578 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008579 JavaScriptFrame* frame = it.frame();
8580 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008581 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008582 ASSERT(unoptimized->contains(frame->pc()));
8583
8584 // Use linear search of the unoptimized code's stack check table to find
8585 // the AST id matching the PC.
8586 Address start = unoptimized->instruction_start();
8587 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008588 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008589 uint32_t table_length = Memory::uint32_at(table_cursor);
8590 table_cursor += kIntSize;
8591 for (unsigned i = 0; i < table_length; ++i) {
8592 // Table entries are (AST id, pc offset) pairs.
8593 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8594 if (pc_offset == target_pc_offset) {
8595 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8596 break;
8597 }
8598 table_cursor += 2 * kIntSize;
8599 }
8600 ASSERT(ast_id != AstNode::kNoNumber);
8601 if (FLAG_trace_osr) {
8602 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8603 function->PrintName();
8604 PrintF("]\n");
8605 }
8606
8607 // Try to compile the optimized code. A true return value from
8608 // CompileOptimized means that compilation succeeded, not necessarily
8609 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008610 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008611 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008612 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8613 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008614 if (data->OsrPcOffset()->value() >= 0) {
8615 if (FLAG_trace_osr) {
8616 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008617 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008618 }
8619 ASSERT(data->OsrAstId()->value() == ast_id);
8620 } else {
8621 // We may never generate the desired OSR entry if we emit an
8622 // early deoptimize.
8623 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008624 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008625 } else {
8626 succeeded = false;
8627 }
8628 }
8629
8630 // Revert to the original stack checks in the original unoptimized code.
8631 if (FLAG_trace_osr) {
8632 PrintF("[restoring original stack checks in ");
8633 function->PrintName();
8634 PrintF("]\n");
8635 }
8636 StackCheckStub check_stub;
8637 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008638 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008639 Deoptimizer::RevertStackCheckCode(*unoptimized,
8640 *check_code,
8641 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008642
8643 // Allow OSR only at nesting level zero again.
8644 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8645
8646 // If the optimization attempt succeeded, return the AST id tagged as a
8647 // smi. This tells the builtin that we need to translate the unoptimized
8648 // frame to an optimized one.
8649 if (succeeded) {
8650 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8651 return Smi::FromInt(ast_id);
8652 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008653 if (function->IsMarkedForLazyRecompilation()) {
8654 function->ReplaceCode(function->shared()->code());
8655 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008656 return Smi::FromInt(-1);
8657 }
8658}
8659
8660
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008661RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8662 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8663 return isolate->heap()->undefined_value();
8664}
8665
8666
danno@chromium.orgc612e022011-11-10 11:38:15 +00008667RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8668 HandleScope scope(isolate);
8669 ASSERT(args.length() >= 2);
8670 CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
8671 Object* receiver = args[0];
8672 int argc = args.length() - 2;
8673
8674 // If there are too many arguments, allocate argv via malloc.
8675 const int argv_small_size = 10;
8676 Handle<Object> argv_small_buffer[argv_small_size];
8677 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8678 Handle<Object>* argv = argv_small_buffer;
8679 if (argc > argv_small_size) {
8680 argv = new Handle<Object>[argc];
8681 if (argv == NULL) return isolate->StackOverflow();
8682 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8683 }
8684
8685 for (int i = 0; i < argc; ++i) {
8686 MaybeObject* maybe = args[1 + i];
8687 Object* object;
8688 if (!maybe->To<Object>(&object)) return maybe;
8689 argv[i] = Handle<Object>(object);
8690 }
8691
8692 bool threw;
8693 Handle<JSReceiver> hfun(fun);
8694 Handle<Object> hreceiver(receiver);
8695 Handle<Object> result =
8696 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8697
8698 if (threw) return Failure::Exception();
8699 return *result;
8700}
8701
8702
lrn@chromium.org34e60782011-09-15 07:25:40 +00008703RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8704 HandleScope scope(isolate);
8705 ASSERT(args.length() == 5);
8706 CONVERT_CHECKED(JSReceiver, fun, args[0]);
8707 Object* receiver = args[1];
8708 CONVERT_CHECKED(JSObject, arguments, args[2]);
8709 CONVERT_CHECKED(Smi, shift, args[3]);
8710 CONVERT_CHECKED(Smi, arity, args[4]);
8711
8712 int offset = shift->value();
8713 int argc = arity->value();
8714 ASSERT(offset >= 0);
8715 ASSERT(argc >= 0);
8716
8717 // If there are too many arguments, allocate argv via malloc.
8718 const int argv_small_size = 10;
8719 Handle<Object> argv_small_buffer[argv_small_size];
8720 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8721 Handle<Object>* argv = argv_small_buffer;
8722 if (argc > argv_small_size) {
8723 argv = new Handle<Object>[argc];
8724 if (argv == NULL) return isolate->StackOverflow();
8725 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8726 }
8727
8728 for (int i = 0; i < argc; ++i) {
8729 MaybeObject* maybe = arguments->GetElement(offset + i);
8730 Object* object;
8731 if (!maybe->To<Object>(&object)) return maybe;
8732 argv[i] = Handle<Object>(object);
8733 }
8734
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008735 bool threw;
lrn@chromium.org34e60782011-09-15 07:25:40 +00008736 Handle<JSReceiver> hfun(fun);
8737 Handle<Object> hreceiver(receiver);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008738 Handle<Object> result =
8739 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008740
8741 if (threw) return Failure::Exception();
8742 return *result;
8743}
8744
8745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008746RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008747 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008748 ASSERT(args.length() == 1);
8749 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8750 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8751}
8752
8753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008754RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008755 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008756 ASSERT(args.length() == 1);
8757 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8758 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8759}
8760
8761
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008762RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008763 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008764 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008765
kasper.lund7276f142008-07-30 08:49:36 +00008766 CONVERT_CHECKED(JSFunction, function, args[0]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008767 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008768 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008769 { MaybeObject* maybe_result =
8770 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008771 if (!maybe_result->ToObject(&result)) return maybe_result;
8772 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008773
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008774 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008775
kasper.lund7276f142008-07-30 08:49:36 +00008776 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008777}
8778
lrn@chromium.org303ada72010-10-27 09:33:13 +00008779
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008780RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8781 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008782 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008783 JSObject* extension_object;
8784 if (args[0]->IsJSObject()) {
8785 extension_object = JSObject::cast(args[0]);
8786 } else {
8787 // Convert the object to a proper JavaScript object.
8788 MaybeObject* maybe_js_object = args[0]->ToObject();
8789 if (!maybe_js_object->To(&extension_object)) {
8790 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8791 HandleScope scope(isolate);
8792 Handle<Object> handle = args.at<Object>(0);
8793 Handle<Object> result =
8794 isolate->factory()->NewTypeError("with_expression",
8795 HandleVector(&handle, 1));
8796 return isolate->Throw(*result);
8797 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008798 return maybe_js_object;
8799 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008800 }
8801 }
8802
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008803 JSFunction* function;
8804 if (args[1]->IsSmi()) {
8805 // A smi sentinel indicates a context nested inside global code rather
8806 // than some function. There is a canonical empty function that can be
8807 // gotten from the global context.
8808 function = isolate->context()->global_context()->closure();
8809 } else {
8810 function = JSFunction::cast(args[1]);
8811 }
8812
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008813 Context* context;
8814 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008815 isolate->heap()->AllocateWithContext(function,
8816 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008817 extension_object);
8818 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008819 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008820 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008821}
8822
8823
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008824RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008825 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008826 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008827 String* name = String::cast(args[0]);
8828 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008829 JSFunction* function;
8830 if (args[2]->IsSmi()) {
8831 // A smi sentinel indicates a context nested inside global code rather
8832 // than some function. There is a canonical empty function that can be
8833 // gotten from the global context.
8834 function = isolate->context()->global_context()->closure();
8835 } else {
8836 function = JSFunction::cast(args[2]);
8837 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008838 Context* context;
8839 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008840 isolate->heap()->AllocateCatchContext(function,
8841 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008842 name,
8843 thrown_object);
8844 if (!maybe_context->To(&context)) return maybe_context;
8845 isolate->set_context(context);
8846 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008847}
8848
8849
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008850RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8851 NoHandleAllocation ha;
8852 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008853 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008854 JSFunction* function;
8855 if (args[1]->IsSmi()) {
8856 // A smi sentinel indicates a context nested inside global code rather
8857 // than some function. There is a canonical empty function that can be
8858 // gotten from the global context.
8859 function = isolate->context()->global_context()->closure();
8860 } else {
8861 function = JSFunction::cast(args[1]);
8862 }
8863 Context* context;
8864 MaybeObject* maybe_context =
8865 isolate->heap()->AllocateBlockContext(function,
8866 isolate->context(),
8867 scope_info);
8868 if (!maybe_context->To(&context)) return maybe_context;
8869 isolate->set_context(context);
8870 return context;
8871}
8872
8873
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008874RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008875 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008876 ASSERT(args.length() == 2);
8877
8878 CONVERT_ARG_CHECKED(Context, context, 0);
8879 CONVERT_ARG_CHECKED(String, name, 1);
8880
8881 int index;
8882 PropertyAttributes attributes;
8883 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008884 BindingFlags binding_flags;
8885 Handle<Object> holder = context->Lookup(name,
8886 flags,
8887 &index,
8888 &attributes,
8889 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008890
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008891 // If the slot was not found the result is true.
8892 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008893 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008894 }
8895
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008896 // If the slot was found in a context, it should be DONT_DELETE.
8897 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008898 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008899 }
8900
8901 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008902 // the global object, or the subject of a with. Try to delete it
8903 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008904 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008905 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008906}
8907
8908
ager@chromium.orga1645e22009-09-09 19:27:10 +00008909// A mechanism to return a pair of Object pointers in registers (if possible).
8910// How this is achieved is calling convention-dependent.
8911// All currently supported x86 compiles uses calling conventions that are cdecl
8912// variants where a 64-bit value is returned in two 32-bit registers
8913// (edx:eax on ia32, r1:r0 on ARM).
8914// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8915// In Win64 calling convention, a struct of two pointers is returned in memory,
8916// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008917#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008918struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008919 MaybeObject* x;
8920 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008921};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008922
lrn@chromium.org303ada72010-10-27 09:33:13 +00008923static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008924 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008925 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8926 // In Win64 they are assigned to a hidden first argument.
8927 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008928}
8929#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008930typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008931static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008932 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008933 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008934}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008935#endif
8936
8937
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008938static inline MaybeObject* Unhole(Heap* heap,
8939 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008940 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008941 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8942 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008943 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008944}
8945
8946
danno@chromium.org40cb8782011-05-25 07:58:50 +00008947static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8948 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008949 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008950 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008951 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008952 JSFunction* context_extension_function =
8953 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008954 // If the holder isn't a context extension object, we just return it
8955 // as the receiver. This allows arguments objects to be used as
8956 // receivers, but only if they are put in the context scope chain
8957 // explicitly via a with-statement.
8958 Object* constructor = holder->map()->constructor();
8959 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008960 // Fall back to using the global object as the implicit receiver if
8961 // the property turns out to be a local variable allocated in a
8962 // context extension object - introduced via eval. Implicit global
8963 // receivers are indicated with the hole value.
8964 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008965}
8966
8967
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008968static ObjectPair LoadContextSlotHelper(Arguments args,
8969 Isolate* isolate,
8970 bool throw_error) {
8971 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008972 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008973
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008974 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008975 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008976 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008977 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008978 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008979
8980 int index;
8981 PropertyAttributes attributes;
8982 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008983 BindingFlags binding_flags;
8984 Handle<Object> holder = context->Lookup(name,
8985 flags,
8986 &index,
8987 &attributes,
8988 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008989
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008990 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008991 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008992 ASSERT(holder->IsContext());
8993 // If the "property" we were looking for is a local variable, the
8994 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008995 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008996 // Use the hole as the receiver to signal that the receiver is implicit
8997 // and that the global receiver should be used (as distinguished from an
8998 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008999 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009000 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009001 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009002 switch (binding_flags) {
9003 case MUTABLE_CHECK_INITIALIZED:
9004 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9005 if (value->IsTheHole()) {
9006 Handle<Object> reference_error =
9007 isolate->factory()->NewReferenceError("not_defined",
9008 HandleVector(&name, 1));
9009 return MakePair(isolate->Throw(*reference_error), NULL);
9010 }
9011 // FALLTHROUGH
9012 case MUTABLE_IS_INITIALIZED:
9013 case IMMUTABLE_IS_INITIALIZED:
9014 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9015 ASSERT(!value->IsTheHole());
9016 return MakePair(value, *receiver);
9017 case IMMUTABLE_CHECK_INITIALIZED:
9018 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9019 case MISSING_BINDING:
9020 UNREACHABLE();
9021 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009022 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009023 }
9024
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009025 // Otherwise, if the slot was found the holder is a context extension
9026 // object, subject of a with, or a global object. We read the named
9027 // property from it.
9028 if (!holder.is_null()) {
9029 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9030 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009031 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009032 Handle<Object> receiver_handle(object->IsGlobalObject()
9033 ? GlobalObject::cast(*object)->global_receiver()
9034 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009035
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009036 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009037 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009038 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009039 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009040 }
9041
9042 if (throw_error) {
9043 // The property doesn't exist - throw exception.
9044 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009045 isolate->factory()->NewReferenceError("not_defined",
9046 HandleVector(&name, 1));
9047 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009048 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009049 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009050 return MakePair(isolate->heap()->undefined_value(),
9051 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009052 }
9053}
9054
9055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009056RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009057 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009058}
9059
9060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009061RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009062 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009063}
9064
9065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009066RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009067 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009068 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009069
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009070 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009071 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009072 CONVERT_ARG_CHECKED(String, name, 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009073 CONVERT_STRICT_MODE_ARG(strict_mode, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009074
9075 int index;
9076 PropertyAttributes attributes;
9077 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009078 BindingFlags binding_flags;
9079 Handle<Object> holder = context->Lookup(name,
9080 flags,
9081 &index,
9082 &attributes,
9083 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009084
9085 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009086 // The property was found in a context slot.
9087 Handle<Context> context = Handle<Context>::cast(holder);
9088 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9089 context->get(index)->IsTheHole()) {
9090 Handle<Object> error =
9091 isolate->factory()->NewReferenceError("not_defined",
9092 HandleVector(&name, 1));
9093 return isolate->Throw(*error);
9094 }
9095 // Ignore if read_only variable.
9096 if ((attributes & READ_ONLY) == 0) {
9097 // Context is a fixed array and set cannot fail.
9098 context->set(index, *value);
9099 } else if (strict_mode == kStrictMode) {
9100 // Setting read only property in strict mode.
9101 Handle<Object> error =
9102 isolate->factory()->NewTypeError("strict_cannot_assign",
9103 HandleVector(&name, 1));
9104 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009105 }
9106 return *value;
9107 }
9108
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009109 // Slow case: The property is not in a context slot. It is either in a
9110 // context extension object, a property of the subject of a with, or a
9111 // property of the global object.
9112 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009113
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009114 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009115 // The property exists on the holder.
9116 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009117 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009118 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009119 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009120
9121 if (strict_mode == kStrictMode) {
9122 // Throw in strict mode (assignment to undefined variable).
9123 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009124 isolate->factory()->NewReferenceError(
9125 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009126 return isolate->Throw(*error);
9127 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009128 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009129 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009130 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009131 }
9132
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009133 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009134 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009135 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009136 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009137 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009138 SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009139 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009140 // Setting read only property in strict mode.
9141 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009142 isolate->factory()->NewTypeError(
9143 "strict_cannot_assign", HandleVector(&name, 1));
9144 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009145 }
9146 return *value;
9147}
9148
9149
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009150RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009151 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009152 ASSERT(args.length() == 1);
9153
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009154 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155}
9156
9157
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009158RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009159 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009160 ASSERT(args.length() == 1);
9161
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009162 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009163}
9164
9165
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009166RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009167 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009168 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009169}
9170
9171
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009172RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009173 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009174 ASSERT(args.length() == 1);
9175
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009176 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009177 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009178 isolate->factory()->NewReferenceError("not_defined",
9179 HandleVector(&name, 1));
9180 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009181}
9182
9183
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009184RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009185 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009186
9187 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009188 if (isolate->stack_guard()->IsStackOverflow()) {
9189 NoHandleAllocation na;
9190 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009191 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009192
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009193 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009194}
9195
9196
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009197static int StackSize() {
9198 int n = 0;
9199 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9200 return n;
9201}
9202
9203
9204static void PrintTransition(Object* result) {
9205 // indentation
9206 { const int nmax = 80;
9207 int n = StackSize();
9208 if (n <= nmax)
9209 PrintF("%4d:%*s", n, n, "");
9210 else
9211 PrintF("%4d:%*s", n, nmax, "...");
9212 }
9213
9214 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009215 JavaScriptFrame::PrintTop(stdout, true, false);
9216 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009217 } else {
9218 // function result
9219 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009220 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009221 PrintF("\n");
9222 }
9223}
9224
9225
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009226RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceElementsKindTransition) {
9227 ASSERT(args.length() == 5);
9228 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9229 CONVERT_SMI_ARG_CHECKED(from_kind, 1);
9230 CONVERT_ARG_CHECKED(FixedArrayBase, from_elements, 2);
9231 CONVERT_SMI_ARG_CHECKED(to_kind, 3);
9232 CONVERT_ARG_CHECKED(FixedArrayBase, to_elements, 4);
9233 NoHandleAllocation ha;
9234 PrintF("*");
9235 obj->PrintElementsTransition(stdout,
9236 static_cast<ElementsKind>(from_kind), *from_elements,
9237 static_cast<ElementsKind>(to_kind), *to_elements);
9238 return isolate->heap()->undefined_value();
9239}
9240
9241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009242RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009243 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009244 NoHandleAllocation ha;
9245 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009246 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009247}
9248
9249
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009250RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009251 NoHandleAllocation ha;
9252 PrintTransition(args[0]);
9253 return args[0]; // return TOS
9254}
9255
9256
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009257RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009258 NoHandleAllocation ha;
9259 ASSERT(args.length() == 1);
9260
9261#ifdef DEBUG
9262 if (args[0]->IsString()) {
9263 // If we have a string, assume it's a code "marker"
9264 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009265 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009266 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009267 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9268 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009269 } else {
9270 PrintF("DebugPrint: ");
9271 }
9272 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009273 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009274 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009275 HeapObject::cast(args[0])->map()->Print();
9276 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009277#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009278 // ShortPrint is available in release mode. Print is not.
9279 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009280#endif
9281 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009282 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009283
9284 return args[0]; // return TOS
9285}
9286
9287
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009288RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009289 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009290 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009291 isolate->PrintStack();
9292 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009293}
9294
9295
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009296RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009297 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009298 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009299
9300 // According to ECMA-262, section 15.9.1, page 117, the precision of
9301 // the number in a Date object representing a particular instant in
9302 // time is milliseconds. Therefore, we floor the result of getting
9303 // the OS time.
9304 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009305 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009306}
9307
9308
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009309RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009310 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009311 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009312
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009313 CONVERT_ARG_CHECKED(String, str, 0);
9314 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009315
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009316 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009317
9318 MaybeObject* maybe_result_array =
9319 output->EnsureCanContainNonSmiElements();
9320 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009321 RUNTIME_ASSERT(output->HasFastElements());
9322
9323 AssertNoAllocation no_allocation;
9324
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009325 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009326 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9327 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009328 String::FlatContent str_content = str->GetFlatContent();
9329 if (str_content.IsAscii()) {
9330 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009331 output_array,
9332 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009333 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009334 ASSERT(str_content.IsTwoByte());
9335 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009336 output_array,
9337 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009338 }
9339
9340 if (result) {
9341 return *output;
9342 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009343 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009344 }
9345}
9346
9347
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009348RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009349 NoHandleAllocation ha;
9350 ASSERT(args.length() == 1);
9351
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009352 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009353 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009354 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009355}
9356
9357
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009358RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009359 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009360 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009361
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009362 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009363}
9364
9365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009366RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009367 NoHandleAllocation ha;
9368 ASSERT(args.length() == 1);
9369
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009370 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009371 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009372}
9373
9374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009375RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009376 ASSERT(args.length() == 1);
9377 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009378 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009379 return JSGlobalObject::cast(global)->global_receiver();
9380}
9381
9382
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009383RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009384 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009385 ASSERT_EQ(1, args.length());
9386 CONVERT_ARG_CHECKED(String, source, 0);
9387
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009388 source = Handle<String>(source->TryFlattenGetString());
9389 // Optimized fast case where we only have ascii characters.
9390 Handle<Object> result;
9391 if (source->IsSeqAsciiString()) {
9392 result = JsonParser<true>::Parse(source);
9393 } else {
9394 result = JsonParser<false>::Parse(source);
9395 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009396 if (result.is_null()) {
9397 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009398 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009399 return Failure::Exception();
9400 }
9401 return *result;
9402}
9403
9404
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009405bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9406 Handle<Context> context) {
9407 if (context->allow_code_gen_from_strings()->IsFalse()) {
9408 // Check with callback if set.
9409 AllowCodeGenerationFromStringsCallback callback =
9410 isolate->allow_code_gen_callback();
9411 if (callback == NULL) {
9412 // No callback set and code generation disallowed.
9413 return false;
9414 } else {
9415 // Callback set. Let it decide if code generation is allowed.
9416 VMState state(isolate, EXTERNAL);
9417 return callback(v8::Utils::ToLocal(context));
9418 }
9419 }
9420 return true;
9421}
9422
9423
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009424RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009425 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009426 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009427 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009428
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009429 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009430 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009431
9432 // Check if global context allows code generation from
9433 // strings. Throw an exception if it doesn't.
9434 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9435 return isolate->Throw(*isolate->factory()->NewError(
9436 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9437 }
9438
9439 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009440 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9441 source, context, true, kNonStrictMode, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009442 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009443 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009444 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9445 context,
9446 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009447 return *fun;
9448}
9449
9450
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009451static ObjectPair CompileGlobalEval(Isolate* isolate,
9452 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009453 Handle<Object> receiver,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009454 StrictModeFlag strict_mode,
9455 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009456 Handle<Context> context = Handle<Context>(isolate->context());
9457 Handle<Context> global_context = Handle<Context>(context->global_context());
9458
9459 // Check if global context allows code generation from
9460 // strings. Throw an exception if it doesn't.
9461 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9462 isolate->Throw(*isolate->factory()->NewError(
9463 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9464 return MakePair(Failure::Exception(), NULL);
9465 }
9466
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009467 // Deal with a normal eval call with a string argument. Compile it
9468 // and return the compiled function bound in the local context.
9469 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9470 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009471 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009472 context->IsGlobalContext(),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009473 strict_mode,
9474 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009475 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009476 Handle<JSFunction> compiled =
9477 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009478 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009479 return MakePair(*compiled, *receiver);
9480}
9481
9482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009483RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009484 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009485
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009486 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009487 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009488
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009489 // If "eval" didn't refer to the original GlobalEval, it's not a
9490 // direct call to eval.
9491 // (And even if it is, but the first argument isn't a string, just let
9492 // execution default to an indirect call to eval, which will also return
9493 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009494 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009495 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009496 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009497 }
9498
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009499 CONVERT_STRICT_MODE_ARG(strict_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009500 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009501 return CompileGlobalEval(isolate,
9502 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009503 args.at<Object>(2),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009504 strict_mode,
9505 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009506}
9507
9508
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009509RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009510 // This utility adjusts the property attributes for newly created Function
9511 // object ("new Function(...)") by changing the map.
9512 // All it does is changing the prototype property to enumerable
9513 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009514 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009515 ASSERT(args.length() == 1);
9516 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009517
9518 Handle<Map> map = func->shared()->strict_mode()
9519 ? isolate->strict_mode_function_instance_map()
9520 : isolate->function_instance_map();
9521
9522 ASSERT(func->map()->instance_type() == map->instance_type());
9523 ASSERT(func->map()->instance_size() == map->instance_size());
9524 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009525 return *func;
9526}
9527
9528
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009529RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009530 // Allocate a block of memory in NewSpace (filled with a filler).
9531 // Use as fallback for allocation in generated code when NewSpace
9532 // is full.
9533 ASSERT(args.length() == 1);
9534 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9535 int size = size_smi->value();
9536 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9537 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009538 Heap* heap = isolate->heap();
9539 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009540 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009541 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009542 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009543 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009544 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009545 }
9546 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009547 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009548}
9549
9550
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009551// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009552// array. Returns true if the element was pushed on the stack and
9553// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009554RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009555 ASSERT(args.length() == 2);
9556 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009557 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009558 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009559 int length = Smi::cast(array->length())->value();
9560 FixedArray* elements = FixedArray::cast(array->elements());
9561 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009562 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009563 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009564 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009565 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009566 { MaybeObject* maybe_obj =
9567 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009568 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9569 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009570 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009571}
9572
9573
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009574/**
9575 * A simple visitor visits every element of Array's.
9576 * The backend storage can be a fixed array for fast elements case,
9577 * or a dictionary for sparse array. Since Dictionary is a subtype
9578 * of FixedArray, the class can be used by both fast and slow cases.
9579 * The second parameter of the constructor, fast_elements, specifies
9580 * whether the storage is a FixedArray or Dictionary.
9581 *
9582 * An index limit is used to deal with the situation that a result array
9583 * length overflows 32-bit non-negative integer.
9584 */
9585class ArrayConcatVisitor {
9586 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009587 ArrayConcatVisitor(Isolate* isolate,
9588 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009589 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009590 isolate_(isolate),
9591 storage_(Handle<FixedArray>::cast(
9592 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009593 index_offset_(0u),
9594 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009595
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009596 ~ArrayConcatVisitor() {
9597 clear_storage();
9598 }
9599
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009600 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009601 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009602 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009603
9604 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009605 if (index < static_cast<uint32_t>(storage_->length())) {
9606 storage_->set(index, *elm);
9607 return;
9608 }
9609 // Our initial estimate of length was foiled, possibly by
9610 // getters on the arrays increasing the length of later arrays
9611 // during iteration.
9612 // This shouldn't happen in anything but pathological cases.
9613 SetDictionaryMode(index);
9614 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009615 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009616 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009617 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009618 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009619 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009620 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009621 // Dictionary needed to grow.
9622 clear_storage();
9623 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009624 }
9625}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009626
9627 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009628 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9629 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009630 } else {
9631 index_offset_ += delta;
9632 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009633 }
9634
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009635 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009636 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009637 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009638 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009639 Handle<Map> map;
9640 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009641 map = isolate_->factory()->GetElementsTransitionMap(array,
9642 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009643 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009644 map = isolate_->factory()->GetElementsTransitionMap(array,
9645 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009646 }
9647 array->set_map(*map);
9648 array->set_length(*length);
9649 array->set_elements(*storage_);
9650 return array;
9651 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009652
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009653 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009654 // Convert storage to dictionary mode.
9655 void SetDictionaryMode(uint32_t index) {
9656 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009657 Handle<FixedArray> current_storage(*storage_);
9658 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009659 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009660 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9661 for (uint32_t i = 0; i < current_length; i++) {
9662 HandleScope loop_scope;
9663 Handle<Object> element(current_storage->get(i));
9664 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009665 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009666 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009667 if (!new_storage.is_identical_to(slow_storage)) {
9668 slow_storage = loop_scope.CloseAndEscape(new_storage);
9669 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009670 }
9671 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009672 clear_storage();
9673 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009674 fast_elements_ = false;
9675 }
9676
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009677 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009678 isolate_->global_handles()->Destroy(
9679 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009680 }
9681
9682 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009683 storage_ = Handle<FixedArray>::cast(
9684 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009685 }
9686
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009687 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009688 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009689 // Index after last seen index. Always less than or equal to
9690 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009691 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009692 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009693};
9694
9695
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009696static uint32_t EstimateElementCount(Handle<JSArray> array) {
9697 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9698 int element_count = 0;
9699 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009700 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009701 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009702 // Fast elements can't have lengths that are not representable by
9703 // a 32-bit signed integer.
9704 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9705 int fast_length = static_cast<int>(length);
9706 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9707 for (int i = 0; i < fast_length; i++) {
9708 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009709 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009710 break;
9711 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009712 case FAST_DOUBLE_ELEMENTS:
9713 // TODO(1810): Decide if it's worthwhile to implement this.
9714 UNREACHABLE();
9715 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009716 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009717 Handle<NumberDictionary> dictionary(
9718 NumberDictionary::cast(array->elements()));
9719 int capacity = dictionary->Capacity();
9720 for (int i = 0; i < capacity; i++) {
9721 Handle<Object> key(dictionary->KeyAt(i));
9722 if (dictionary->IsKey(*key)) {
9723 element_count++;
9724 }
9725 }
9726 break;
9727 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009728 case NON_STRICT_ARGUMENTS_ELEMENTS:
9729 case EXTERNAL_BYTE_ELEMENTS:
9730 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9731 case EXTERNAL_SHORT_ELEMENTS:
9732 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9733 case EXTERNAL_INT_ELEMENTS:
9734 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9735 case EXTERNAL_FLOAT_ELEMENTS:
9736 case EXTERNAL_DOUBLE_ELEMENTS:
9737 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009738 // External arrays are always dense.
9739 return length;
9740 }
9741 // As an estimate, we assume that the prototype doesn't contain any
9742 // inherited elements.
9743 return element_count;
9744}
9745
9746
9747
9748template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009749static void IterateExternalArrayElements(Isolate* isolate,
9750 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009751 bool elements_are_ints,
9752 bool elements_are_guaranteed_smis,
9753 ArrayConcatVisitor* visitor) {
9754 Handle<ExternalArrayClass> array(
9755 ExternalArrayClass::cast(receiver->elements()));
9756 uint32_t len = static_cast<uint32_t>(array->length());
9757
9758 ASSERT(visitor != NULL);
9759 if (elements_are_ints) {
9760 if (elements_are_guaranteed_smis) {
9761 for (uint32_t j = 0; j < len; j++) {
9762 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009763 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009764 visitor->visit(j, e);
9765 }
9766 } else {
9767 for (uint32_t j = 0; j < len; j++) {
9768 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009769 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009770 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9771 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9772 visitor->visit(j, e);
9773 } else {
9774 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009775 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009776 visitor->visit(j, e);
9777 }
9778 }
9779 }
9780 } else {
9781 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009782 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009783 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009784 visitor->visit(j, e);
9785 }
9786 }
9787}
9788
9789
9790// Used for sorting indices in a List<uint32_t>.
9791static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9792 uint32_t a = *ap;
9793 uint32_t b = *bp;
9794 return (a == b) ? 0 : (a < b) ? -1 : 1;
9795}
9796
9797
9798static void CollectElementIndices(Handle<JSObject> object,
9799 uint32_t range,
9800 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009801 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009802 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009803 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009804 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009805 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9806 uint32_t length = static_cast<uint32_t>(elements->length());
9807 if (range < length) length = range;
9808 for (uint32_t i = 0; i < length; i++) {
9809 if (!elements->get(i)->IsTheHole()) {
9810 indices->Add(i);
9811 }
9812 }
9813 break;
9814 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009815 case FAST_DOUBLE_ELEMENTS: {
9816 // TODO(1810): Decide if it's worthwhile to implement this.
9817 UNREACHABLE();
9818 break;
9819 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009820 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009821 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009822 uint32_t capacity = dict->Capacity();
9823 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009824 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009825 Handle<Object> k(dict->KeyAt(j));
9826 if (dict->IsKey(*k)) {
9827 ASSERT(k->IsNumber());
9828 uint32_t index = static_cast<uint32_t>(k->Number());
9829 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009830 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009831 }
9832 }
9833 }
9834 break;
9835 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009836 default: {
9837 int dense_elements_length;
9838 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009839 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009840 dense_elements_length =
9841 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009842 break;
9843 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009844 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009845 dense_elements_length =
9846 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009847 break;
9848 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009849 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009850 dense_elements_length =
9851 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009852 break;
9853 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009854 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009855 dense_elements_length =
9856 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009857 break;
9858 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009859 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009860 dense_elements_length =
9861 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009862 break;
9863 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009864 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009865 dense_elements_length =
9866 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009867 break;
9868 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009869 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009870 dense_elements_length =
9871 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009872 break;
9873 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009874 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009875 dense_elements_length =
9876 ExternalFloatArray::cast(object->elements())->length();
9877 break;
9878 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009879 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009880 dense_elements_length =
9881 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009882 break;
9883 }
9884 default:
9885 UNREACHABLE();
9886 dense_elements_length = 0;
9887 break;
9888 }
9889 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9890 if (range <= length) {
9891 length = range;
9892 // We will add all indices, so we might as well clear it first
9893 // and avoid duplicates.
9894 indices->Clear();
9895 }
9896 for (uint32_t i = 0; i < length; i++) {
9897 indices->Add(i);
9898 }
9899 if (length == range) return; // All indices accounted for already.
9900 break;
9901 }
9902 }
9903
9904 Handle<Object> prototype(object->GetPrototype());
9905 if (prototype->IsJSObject()) {
9906 // The prototype will usually have no inherited element indices,
9907 // but we have to check.
9908 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9909 }
9910}
9911
9912
9913/**
9914 * A helper function that visits elements of a JSArray in numerical
9915 * order.
9916 *
9917 * The visitor argument called for each existing element in the array
9918 * with the element index and the element's value.
9919 * Afterwards it increments the base-index of the visitor by the array
9920 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009921 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009922 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009923static bool IterateElements(Isolate* isolate,
9924 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009925 ArrayConcatVisitor* visitor) {
9926 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9927 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009928 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009929 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009930 // Run through the elements FixedArray and use HasElement and GetElement
9931 // to check the prototype for missing elements.
9932 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9933 int fast_length = static_cast<int>(length);
9934 ASSERT(fast_length <= elements->length());
9935 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009936 HandleScope loop_scope(isolate);
9937 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009938 if (!element_value->IsTheHole()) {
9939 visitor->visit(j, element_value);
9940 } else if (receiver->HasElement(j)) {
9941 // Call GetElement on receiver, not its prototype, or getters won't
9942 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009943 element_value = Object::GetElement(receiver, j);
9944 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009945 visitor->visit(j, element_value);
9946 }
9947 }
9948 break;
9949 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009950 case FAST_DOUBLE_ELEMENTS: {
9951 // TODO(1810): Decide if it's worthwhile to implement this.
9952 UNREACHABLE();
9953 break;
9954 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009955 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009956 Handle<NumberDictionary> dict(receiver->element_dictionary());
9957 List<uint32_t> indices(dict->Capacity() / 2);
9958 // Collect all indices in the object and the prototypes less
9959 // than length. This might introduce duplicates in the indices list.
9960 CollectElementIndices(receiver, length, &indices);
9961 indices.Sort(&compareUInt32);
9962 int j = 0;
9963 int n = indices.length();
9964 while (j < n) {
9965 HandleScope loop_scope;
9966 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009967 Handle<Object> element = Object::GetElement(receiver, index);
9968 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009969 visitor->visit(index, element);
9970 // Skip to next different index (i.e., omit duplicates).
9971 do {
9972 j++;
9973 } while (j < n && indices[j] == index);
9974 }
9975 break;
9976 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009977 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009978 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9979 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009980 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009981 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009982 visitor->visit(j, e);
9983 }
9984 break;
9985 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009986 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009987 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009988 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009989 break;
9990 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009991 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009992 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009993 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009994 break;
9995 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009996 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009997 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009998 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009999 break;
10000 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010001 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010002 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010003 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010004 break;
10005 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010006 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010007 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010008 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010009 break;
10010 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010011 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010012 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010013 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010014 break;
10015 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010016 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010017 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010018 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010019 break;
10020 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010021 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010022 IterateExternalArrayElements<ExternalDoubleArray, double>(
10023 isolate, receiver, false, false, visitor);
10024 break;
10025 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010026 default:
10027 UNREACHABLE();
10028 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010029 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010030 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010031 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010032}
10033
10034
10035/**
10036 * Array::concat implementation.
10037 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010038 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010039 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010040 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010041RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010042 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010043 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010044
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010045 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10046 int argument_count = static_cast<int>(arguments->length()->Number());
10047 RUNTIME_ASSERT(arguments->HasFastElements());
10048 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010049
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010050 // Pass 1: estimate the length and number of elements of the result.
10051 // The actual length can be larger if any of the arguments have getters
10052 // that mutate other arguments (but will otherwise be precise).
10053 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010054
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010055 uint32_t estimate_result_length = 0;
10056 uint32_t estimate_nof_elements = 0;
10057 {
10058 for (int i = 0; i < argument_count; i++) {
10059 HandleScope loop_scope;
10060 Handle<Object> obj(elements->get(i));
10061 uint32_t length_estimate;
10062 uint32_t element_estimate;
10063 if (obj->IsJSArray()) {
10064 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010065 // TODO(1810): Find out if it's worthwhile to properly support
10066 // arbitrary ElementsKinds. For now, pessimistically transition to
10067 // FAST_ELEMENTS.
10068 if (array->HasFastDoubleElements()) {
10069 array = Handle<JSArray>::cast(
10070 TransitionElementsKind(array, FAST_ELEMENTS));
10071 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010072 length_estimate =
10073 static_cast<uint32_t>(array->length()->Number());
10074 element_estimate =
10075 EstimateElementCount(array);
10076 } else {
10077 length_estimate = 1;
10078 element_estimate = 1;
10079 }
10080 // Avoid overflows by capping at kMaxElementCount.
10081 if (JSObject::kMaxElementCount - estimate_result_length <
10082 length_estimate) {
10083 estimate_result_length = JSObject::kMaxElementCount;
10084 } else {
10085 estimate_result_length += length_estimate;
10086 }
10087 if (JSObject::kMaxElementCount - estimate_nof_elements <
10088 element_estimate) {
10089 estimate_nof_elements = JSObject::kMaxElementCount;
10090 } else {
10091 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010092 }
10093 }
10094 }
10095
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010096 // If estimated number of elements is more than half of length, a
10097 // fixed array (fast case) is more time and space-efficient than a
10098 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010099 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010100
10101 Handle<FixedArray> storage;
10102 if (fast_case) {
10103 // The backing storage array must have non-existing elements to
10104 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010105 storage = isolate->factory()->NewFixedArrayWithHoles(
10106 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010107 } else {
10108 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10109 uint32_t at_least_space_for = estimate_nof_elements +
10110 (estimate_nof_elements >> 2);
10111 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010112 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010113 }
10114
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010115 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010116
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010117 for (int i = 0; i < argument_count; i++) {
10118 Handle<Object> obj(elements->get(i));
10119 if (obj->IsJSArray()) {
10120 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010121 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010122 return Failure::Exception();
10123 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010124 } else {
10125 visitor.visit(0, obj);
10126 visitor.increase_index_offset(1);
10127 }
10128 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010129
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010130 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010131}
10132
10133
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010134// This will not allocate (flatten the string), but it may run
10135// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010136RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010137 NoHandleAllocation ha;
10138 ASSERT(args.length() == 1);
10139
10140 CONVERT_CHECKED(String, string, args[0]);
10141 StringInputBuffer buffer(string);
10142 while (buffer.has_more()) {
10143 uint16_t character = buffer.GetNext();
10144 PrintF("%c", character);
10145 }
10146 return string;
10147}
10148
ager@chromium.org5ec48922009-05-05 07:25:34 +000010149// Moves all own elements of an object, that are below a limit, to positions
10150// starting at zero. All undefined values are placed after non-undefined values,
10151// and are followed by non-existing element. Does not change the length
10152// property.
10153// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010154RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010155 ASSERT(args.length() == 2);
10156 CONVERT_CHECKED(JSObject, object, args[0]);
10157 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10158 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010159}
10160
10161
10162// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010163RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010164 ASSERT(args.length() == 2);
10165 CONVERT_CHECKED(JSArray, from, args[0]);
10166 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010167 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010168 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010169 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010170 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10171 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010172 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010173 } else if (new_elements->map() ==
10174 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010175 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010176 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010177 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010178 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010179 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010180 Object* new_map;
10181 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010182 to->set_map(Map::cast(new_map));
10183 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010184 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010185 Object* obj;
10186 { MaybeObject* maybe_obj = from->ResetElements();
10187 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10188 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010189 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010190 return to;
10191}
10192
10193
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010194// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010195RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010196 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010197 CONVERT_CHECKED(JSObject, object, args[0]);
10198 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010199 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010200 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010201 } else if (object->IsJSArray()) {
10202 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010203 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010204 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010205 }
10206}
10207
10208
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010209RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010210 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010211
10212 ASSERT_EQ(3, args.length());
10213
ager@chromium.orgac091b72010-05-05 07:34:42 +000010214 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010215 Handle<Object> key1 = args.at<Object>(1);
10216 Handle<Object> key2 = args.at<Object>(2);
10217
10218 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010219 if (!key1->ToArrayIndex(&index1)
10220 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010221 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010222 }
10223
ager@chromium.orgac091b72010-05-05 07:34:42 +000010224 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010225 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010226 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010227 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010228 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010229
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010230 RETURN_IF_EMPTY_HANDLE(isolate,
10231 SetElement(jsobject, index1, tmp2, kStrictMode));
10232 RETURN_IF_EMPTY_HANDLE(isolate,
10233 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010234
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010235 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010236}
10237
10238
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010239// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010240// might have elements. Can either return keys (positive integers) or
10241// intervals (pair of a negative integer (-start-1) followed by a
10242// positive (length)) or undefined values.
10243// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010244RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010246 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010247 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010248 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010249 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010250 // Create an array and get all the keys into it, then remove all the
10251 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010252 bool threw = false;
10253 Handle<FixedArray> keys =
10254 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10255 if (threw) return Failure::Exception();
10256
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010257 int keys_length = keys->length();
10258 for (int i = 0; i < keys_length; i++) {
10259 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010260 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010261 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010262 // Zap invalid keys.
10263 keys->set_undefined(i);
10264 }
10265 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010266 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010267 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010268 ASSERT(array->HasFastElements() ||
10269 array->HasFastSmiOnlyElements() ||
10270 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010271 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010272 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010273 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010274 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010275 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010276 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010277 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010278 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010279 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010280 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010281 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010282 }
10283}
10284
10285
10286// DefineAccessor takes an optional final argument which is the
10287// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10288// to the way accessors are implemented, it is set for both the getter
10289// and setter on the first call to DefineAccessor and ignored on
10290// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010291RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010292 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10293 // Compute attributes.
10294 PropertyAttributes attributes = NONE;
10295 if (args.length() == 5) {
10296 CONVERT_CHECKED(Smi, attrs, args[4]);
10297 int value = attrs->value();
10298 // Only attribute bits should be set.
10299 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10300 attributes = static_cast<PropertyAttributes>(value);
10301 }
10302
10303 CONVERT_CHECKED(JSObject, obj, args[0]);
10304 CONVERT_CHECKED(String, name, args[1]);
10305 CONVERT_CHECKED(Smi, flag, args[2]);
10306 CONVERT_CHECKED(JSFunction, fun, args[3]);
10307 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10308}
10309
10310
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010311RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010312 ASSERT(args.length() == 3);
10313 CONVERT_CHECKED(JSObject, obj, args[0]);
10314 CONVERT_CHECKED(String, name, args[1]);
10315 CONVERT_CHECKED(Smi, flag, args[2]);
10316 return obj->LookupAccessor(name, flag->value() == 0);
10317}
10318
10319
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010320#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010321RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010322 ASSERT(args.length() == 0);
10323 return Execution::DebugBreakHelper();
10324}
10325
10326
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010327// Helper functions for wrapping and unwrapping stack frame ids.
10328static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010329 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010330 return Smi::FromInt(id >> 2);
10331}
10332
10333
10334static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10335 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10336}
10337
10338
10339// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010340// args[0]: debug event listener function to set or null or undefined for
10341// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010342// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010343RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010344 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010345 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10346 args[0]->IsUndefined() ||
10347 args[0]->IsNull());
10348 Handle<Object> callback = args.at<Object>(0);
10349 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010350 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010351
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010352 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010353}
10354
10355
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010356RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010357 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010358 isolate->stack_guard()->DebugBreak();
10359 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010360}
10361
10362
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010363static MaybeObject* DebugLookupResultValue(Heap* heap,
10364 Object* receiver,
10365 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010366 LookupResult* result,
10367 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010368 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010369 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010370 case NORMAL:
10371 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010372 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010373 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010374 }
10375 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010376 case FIELD:
10377 value =
10378 JSObject::cast(
10379 result->holder())->FastPropertyAt(result->GetFieldIndex());
10380 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010381 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010382 }
10383 return value;
10384 case CONSTANT_FUNCTION:
10385 return result->GetConstantFunction();
10386 case CALLBACKS: {
10387 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010388 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010389 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10390 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010391 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010392 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010393 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010394 maybe_value = heap->isolate()->pending_exception();
10395 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010396 if (caught_exception != NULL) {
10397 *caught_exception = true;
10398 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010399 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010400 }
10401 return value;
10402 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010403 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010404 }
10405 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010406 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010407 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010408 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010409 case CONSTANT_TRANSITION:
10410 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010411 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010412 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010413 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010414 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010415 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010416 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010417 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010418}
10419
10420
ager@chromium.org32912102009-01-16 10:38:43 +000010421// Get debugger related details for an object property.
10422// args[0]: object holding property
10423// args[1]: name of the property
10424//
10425// The array returned contains the following information:
10426// 0: Property value
10427// 1: Property details
10428// 2: Property value is exception
10429// 3: Getter function if defined
10430// 4: Setter function if defined
10431// Items 2-4 are only filled if the property has either a getter or a setter
10432// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010433RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010434 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010435
10436 ASSERT(args.length() == 2);
10437
10438 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10439 CONVERT_ARG_CHECKED(String, name, 1);
10440
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010441 // Make sure to set the current context to the context before the debugger was
10442 // entered (if the debugger is entered). The reason for switching context here
10443 // is that for some property lookups (accessors and interceptors) callbacks
10444 // into the embedding application can occour, and the embedding application
10445 // could have the assumption that its own global context is the current
10446 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010447 SaveContext save(isolate);
10448 if (isolate->debug()->InDebugger()) {
10449 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010450 }
10451
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010452 // Skip the global proxy as it has no properties and always delegates to the
10453 // real global object.
10454 if (obj->IsJSGlobalProxy()) {
10455 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10456 }
10457
10458
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010459 // Check if the name is trivially convertible to an index and get the element
10460 // if so.
10461 uint32_t index;
10462 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010463 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010464 Object* element_or_char;
10465 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010466 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010467 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10468 return maybe_element_or_char;
10469 }
10470 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010471 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010472 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010473 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010474 }
10475
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010476 // Find the number of objects making up this.
10477 int length = LocalPrototypeChainLength(*obj);
10478
10479 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010480 Handle<JSObject> jsproto = obj;
10481 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010482 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010483 jsproto->LocalLookup(*name, &result);
10484 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010485 // LookupResult is not GC safe as it holds raw object pointers.
10486 // GC can happen later in this code so put the required fields into
10487 // local variables using handles when required for later use.
10488 PropertyType result_type = result.type();
10489 Handle<Object> result_callback_obj;
10490 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010491 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10492 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010493 }
10494 Smi* property_details = result.GetPropertyDetails().AsSmi();
10495 // DebugLookupResultValue can cause GC so details from LookupResult needs
10496 // to be copied to handles before this.
10497 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010498 Object* raw_value;
10499 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010500 DebugLookupResultValue(isolate->heap(), *obj, *name,
10501 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010502 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10503 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010504 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010505
10506 // If the callback object is a fixed array then it contains JavaScript
10507 // getter and/or setter.
10508 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10509 result_callback_obj->IsFixedArray();
10510 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010511 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010512 details->set(0, *value);
10513 details->set(1, property_details);
10514 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010515 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010516 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10517 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10518 }
10519
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010520 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010521 }
10522 if (i < length - 1) {
10523 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10524 }
10525 }
10526
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010527 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010528}
10529
10530
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010531RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010532 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010533
10534 ASSERT(args.length() == 2);
10535
10536 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10537 CONVERT_ARG_CHECKED(String, name, 1);
10538
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010539 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010540 obj->Lookup(*name, &result);
10541 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010542 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010543 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010544 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010545}
10546
10547
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010548// Return the property type calculated from the property details.
10549// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010550RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010551 ASSERT(args.length() == 1);
10552 CONVERT_CHECKED(Smi, details, args[0]);
10553 PropertyType type = PropertyDetails(details).type();
10554 return Smi::FromInt(static_cast<int>(type));
10555}
10556
10557
10558// Return the property attribute calculated from the property details.
10559// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010560RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010561 ASSERT(args.length() == 1);
10562 CONVERT_CHECKED(Smi, details, args[0]);
10563 PropertyAttributes attributes = PropertyDetails(details).attributes();
10564 return Smi::FromInt(static_cast<int>(attributes));
10565}
10566
10567
10568// Return the property insertion index calculated from the property details.
10569// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010570RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010571 ASSERT(args.length() == 1);
10572 CONVERT_CHECKED(Smi, details, args[0]);
10573 int index = PropertyDetails(details).index();
10574 return Smi::FromInt(index);
10575}
10576
10577
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010578// Return property value from named interceptor.
10579// args[0]: object
10580// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010581RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010582 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010583 ASSERT(args.length() == 2);
10584 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10585 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10586 CONVERT_ARG_CHECKED(String, name, 1);
10587
10588 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010589 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010590}
10591
10592
10593// Return element value from indexed interceptor.
10594// args[0]: object
10595// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010596RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010597 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010598 ASSERT(args.length() == 2);
10599 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10600 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10601 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10602
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010603 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010604}
10605
10606
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010607RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010608 ASSERT(args.length() >= 1);
10609 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010610 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010611 if (isolate->debug()->break_id() == 0 ||
10612 break_id != isolate->debug()->break_id()) {
10613 return isolate->Throw(
10614 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010615 }
10616
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010617 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010618}
10619
10620
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010621RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010622 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623 ASSERT(args.length() == 1);
10624
10625 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010626 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010627 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10628 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010629 if (!maybe_result->ToObject(&result)) return maybe_result;
10630 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010631
10632 // Count all frames which are relevant to debugging stack trace.
10633 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010634 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010635 if (id == StackFrame::NO_ID) {
10636 // If there is no JavaScript stack frame count is 0.
10637 return Smi::FromInt(0);
10638 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010639
10640 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10641 n += it.frame()->GetInlineCount();
10642 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010643 return Smi::FromInt(n);
10644}
10645
10646
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010647class FrameInspector {
10648 public:
10649 FrameInspector(JavaScriptFrame* frame,
10650 int inlined_frame_index,
10651 Isolate* isolate)
10652 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10653 // Calculate the deoptimized frame.
10654 if (frame->is_optimized()) {
10655 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10656 frame, inlined_frame_index, isolate);
10657 }
10658 has_adapted_arguments_ = frame_->has_adapted_arguments();
10659 is_optimized_ = frame_->is_optimized();
10660 }
10661
10662 ~FrameInspector() {
10663 // Get rid of the calculated deoptimized frame if any.
10664 if (deoptimized_frame_ != NULL) {
10665 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10666 isolate_);
10667 }
10668 }
10669
10670 int GetParametersCount() {
10671 return is_optimized_
10672 ? deoptimized_frame_->parameters_count()
10673 : frame_->ComputeParametersCount();
10674 }
10675 int expression_count() { return deoptimized_frame_->expression_count(); }
10676 Object* GetFunction() {
10677 return is_optimized_
10678 ? deoptimized_frame_->GetFunction()
10679 : frame_->function();
10680 }
10681 Object* GetParameter(int index) {
10682 return is_optimized_
10683 ? deoptimized_frame_->GetParameter(index)
10684 : frame_->GetParameter(index);
10685 }
10686 Object* GetExpression(int index) {
10687 return is_optimized_
10688 ? deoptimized_frame_->GetExpression(index)
10689 : frame_->GetExpression(index);
10690 }
10691
10692 // To inspect all the provided arguments the frame might need to be
10693 // replaced with the arguments frame.
10694 void SetArgumentsFrame(JavaScriptFrame* frame) {
10695 ASSERT(has_adapted_arguments_);
10696 frame_ = frame;
10697 is_optimized_ = frame_->is_optimized();
10698 ASSERT(!is_optimized_);
10699 }
10700
10701 private:
10702 JavaScriptFrame* frame_;
10703 DeoptimizedFrameInfo* deoptimized_frame_;
10704 Isolate* isolate_;
10705 bool is_optimized_;
10706 bool has_adapted_arguments_;
10707
10708 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10709};
10710
10711
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010712static const int kFrameDetailsFrameIdIndex = 0;
10713static const int kFrameDetailsReceiverIndex = 1;
10714static const int kFrameDetailsFunctionIndex = 2;
10715static const int kFrameDetailsArgumentCountIndex = 3;
10716static const int kFrameDetailsLocalCountIndex = 4;
10717static const int kFrameDetailsSourcePositionIndex = 5;
10718static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010719static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010720static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010721static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010722
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010723
10724static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10725 JavaScriptFrame* frame) {
10726 SaveContext* save = isolate->save_context();
10727 while (save != NULL && !save->IsBelowFrame(frame)) {
10728 save = save->prev();
10729 }
10730 ASSERT(save != NULL);
10731 return save;
10732}
10733
10734
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010735// Return an array with frame details
10736// args[0]: number: break id
10737// args[1]: number: frame index
10738//
10739// The array returned contains the following information:
10740// 0: Frame id
10741// 1: Receiver
10742// 2: Function
10743// 3: Argument count
10744// 4: Local count
10745// 5: Source position
10746// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010747// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010748// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010749// Arguments name, value
10750// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010751// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010752RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010753 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010754 ASSERT(args.length() == 2);
10755
10756 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010757 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010758 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10759 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010760 if (!maybe_check->ToObject(&check)) return maybe_check;
10761 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010762 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010763 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010764
10765 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010766 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010767 if (id == StackFrame::NO_ID) {
10768 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010769 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010770 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010771
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010772 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010773
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010774 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010775 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010776 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010777 if (index < count + it.frame()->GetInlineCount()) break;
10778 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010779 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010780 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010781
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010782 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010783 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010784 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010785 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010786 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010787
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010788 // Traverse the saved contexts chain to find the active context for the
10789 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010790 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010791
10792 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010793 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010794
10795 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010796 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010797 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010798
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010799 // Check for constructor frame. Inlined frames cannot be construct calls.
10800 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010801 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010802 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010803
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010804 // Get scope info and read from it for local variable information.
10805 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010806 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010807 Handle<ScopeInfo> scope_info(shared->scope_info());
10808 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010809
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010810 // Get the locals names and values into a temporary array.
10811 //
10812 // TODO(1240907): Hide compiler-introduced stack variables
10813 // (e.g. .result)? For users of the debugger, they will probably be
10814 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010815 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010816 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010817
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010818 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010819 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010820 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010821 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010822 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010823 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010824 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010825 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010826 // Get the context containing declarations.
10827 Handle<Context> context(
10828 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010829 for (; i < scope_info->LocalCount(); ++i) {
10830 Handle<String> name(scope_info->LocalName(i));
10831 VariableMode mode;
10832 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010833 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010834 locals->set(i * 2 + 1, context->get(
10835 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010836 }
10837 }
10838
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010839 // Check whether this frame is positioned at return. If not top
10840 // frame or if the frame is optimized it cannot be at a return.
10841 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010842 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010843 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010844 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010845
10846 // If positioned just before return find the value to be returned and add it
10847 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010848 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010849 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010850 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010851 Address internal_frame_sp = NULL;
10852 while (!it2.done()) {
10853 if (it2.frame()->is_internal()) {
10854 internal_frame_sp = it2.frame()->sp();
10855 } else {
10856 if (it2.frame()->is_java_script()) {
10857 if (it2.frame()->id() == it.frame()->id()) {
10858 // The internal frame just before the JavaScript frame contains the
10859 // value to return on top. A debug break at return will create an
10860 // internal frame to store the return value (eax/rax/r0) before
10861 // entering the debug break exit frame.
10862 if (internal_frame_sp != NULL) {
10863 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010864 Handle<Object>(Memory::Object_at(internal_frame_sp),
10865 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010866 break;
10867 }
10868 }
10869 }
10870
10871 // Indicate that the previous frame was not an internal frame.
10872 internal_frame_sp = NULL;
10873 }
10874 it2.Advance();
10875 }
10876 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010877
10878 // Now advance to the arguments adapter frame (if any). It contains all
10879 // the provided parameters whereas the function frame always have the number
10880 // of arguments matching the functions parameters. The rest of the
10881 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010882 if (it.frame()->has_adapted_arguments()) {
10883 it.AdvanceToArgumentsFrame();
10884 frame_inspector.SetArgumentsFrame(it.frame());
10885 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010886
10887 // Find the number of arguments to fill. At least fill the number of
10888 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010889 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010890 if (argument_count < frame_inspector.GetParametersCount()) {
10891 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010892 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010893#ifdef DEBUG
10894 if (it.frame()->is_optimized()) {
10895 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10896 }
10897#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010898
10899 // Calculate the size of the result.
10900 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010901 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010902 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010903 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010904
10905 // Add the frame id.
10906 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10907
10908 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010909 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010910
10911 // Add the arguments count.
10912 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10913
10914 // Add the locals count
10915 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010916 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010917
10918 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010919 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010920 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10921 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010922 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010923 }
10924
10925 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010926 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010927
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010928 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010929 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010930
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010931 // Add flags to indicate information on whether this frame is
10932 // bit 0: invoked in the debugger context.
10933 // bit 1: optimized frame.
10934 // bit 2: inlined in optimized frame
10935 int flags = 0;
10936 if (*save->context() == *isolate->debug()->debug_context()) {
10937 flags |= 1 << 0;
10938 }
10939 if (it.frame()->is_optimized()) {
10940 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010941 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010942 }
10943 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010944
10945 // Fill the dynamic part.
10946 int details_index = kFrameDetailsFirstDynamicIndex;
10947
10948 // Add arguments name and value.
10949 for (int i = 0; i < argument_count; i++) {
10950 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010951 if (i < scope_info->ParameterCount()) {
10952 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010953 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010954 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010955 }
10956
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010957 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010958 if (i < it.frame()->ComputeParametersCount()) {
10959 // Get the value from the stack.
10960 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010961 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010962 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010963 }
10964 }
10965
10966 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010967 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010968 details->set(details_index++, locals->get(i));
10969 }
10970
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010971 // Add the value being returned.
10972 if (at_return) {
10973 details->set(details_index++, *return_value);
10974 }
10975
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010976 // Add the receiver (same as in function frame).
10977 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10978 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010979 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010980 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10981 // If the receiver is not a JSObject and the function is not a
10982 // builtin or strict-mode we have hit an optimization where a
10983 // value object is not converted into a wrapped JS objects. To
10984 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010985 // by creating correct wrapper object based on the calling frame's
10986 // global context.
10987 it.Advance();
10988 Handle<Context> calling_frames_global_context(
10989 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010990 receiver =
10991 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010992 }
10993 details->set(kFrameDetailsReceiverIndex, *receiver);
10994
10995 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010996 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010997}
10998
10999
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011000// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011001static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011002 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011003 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011004 Handle<Context> context,
11005 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011006 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011007 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11008 VariableMode mode;
11009 InitializationFlag init_flag;
11010 int context_index = scope_info->ContextSlotIndex(
11011 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011012
whesse@chromium.org7b260152011-06-20 15:33:18 +000011013 RETURN_IF_EMPTY_HANDLE_VALUE(
11014 isolate,
11015 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011016 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011017 Handle<Object>(context->get(context_index), isolate),
11018 NONE,
11019 kNonStrictMode),
11020 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011021 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011022
11023 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011024}
11025
11026
11027// Create a plain JSObject which materializes the local scope for the specified
11028// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011029static Handle<JSObject> MaterializeLocalScope(
11030 Isolate* isolate,
11031 JavaScriptFrame* frame,
11032 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011033 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011034 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011035 Handle<ScopeInfo> scope_info(shared->scope_info());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011036 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011037
11038 // Allocate and initialize a JSObject with all the arguments, stack locals
11039 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011040 Handle<JSObject> local_scope =
11041 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011042
11043 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011044 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011045 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011046 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011047 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011048 Handle<String>(scope_info->ParameterName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011049 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011050 NONE,
11051 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011052 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011053 }
11054
11055 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011056 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011057 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011058 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011059 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011060 Handle<String>(scope_info->StackLocalName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011061 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011062 NONE,
11063 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011064 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011065 }
11066
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011067 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011068 // Third fill all context locals.
11069 Handle<Context> frame_context(Context::cast(frame->context()));
11070 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011071 if (!CopyContextLocalsToScopeObject(
11072 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011073 return Handle<JSObject>();
11074 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011075
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011076 // Finally copy any properties from the function context extension.
11077 // These will be variables introduced by eval.
11078 if (function_context->closure() == *function) {
11079 if (function_context->has_extension() &&
11080 !function_context->IsGlobalContext()) {
11081 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011082 bool threw = false;
11083 Handle<FixedArray> keys =
11084 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11085 if (threw) return Handle<JSObject>();
11086
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011087 for (int i = 0; i < keys->length(); i++) {
11088 // Names of variables introduced by eval are strings.
11089 ASSERT(keys->get(i)->IsString());
11090 Handle<String> key(String::cast(keys->get(i)));
11091 RETURN_IF_EMPTY_HANDLE_VALUE(
11092 isolate,
11093 SetProperty(local_scope,
11094 key,
11095 GetProperty(ext, key),
11096 NONE,
11097 kNonStrictMode),
11098 Handle<JSObject>());
11099 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011100 }
11101 }
11102 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011103
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011104 return local_scope;
11105}
11106
11107
11108// Create a plain JSObject which materializes the closure content for the
11109// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011110static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11111 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011112 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011113
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011114 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011115 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011116
11117 // Allocate and initialize a JSObject with all the content of theis function
11118 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011119 Handle<JSObject> closure_scope =
11120 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011121
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011122 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011123 if (!CopyContextLocalsToScopeObject(
11124 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011125 return Handle<JSObject>();
11126 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011127
11128 // Finally copy any properties from the function context extension. This will
11129 // be variables introduced by eval.
11130 if (context->has_extension()) {
11131 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011132 bool threw = false;
11133 Handle<FixedArray> keys =
11134 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11135 if (threw) return Handle<JSObject>();
11136
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011137 for (int i = 0; i < keys->length(); i++) {
11138 // Names of variables introduced by eval are strings.
11139 ASSERT(keys->get(i)->IsString());
11140 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011141 RETURN_IF_EMPTY_HANDLE_VALUE(
11142 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011143 SetProperty(closure_scope,
11144 key,
11145 GetProperty(ext, key),
11146 NONE,
11147 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011148 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011149 }
11150 }
11151
11152 return closure_scope;
11153}
11154
11155
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011156// Create a plain JSObject which materializes the scope for the specified
11157// catch context.
11158static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11159 Handle<Context> context) {
11160 ASSERT(context->IsCatchContext());
11161 Handle<String> name(String::cast(context->extension()));
11162 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11163 Handle<JSObject> catch_scope =
11164 isolate->factory()->NewJSObject(isolate->object_function());
11165 RETURN_IF_EMPTY_HANDLE_VALUE(
11166 isolate,
11167 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11168 Handle<JSObject>());
11169 return catch_scope;
11170}
11171
11172
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011173// Create a plain JSObject which materializes the block scope for the specified
11174// block context.
11175static Handle<JSObject> MaterializeBlockScope(
11176 Isolate* isolate,
11177 Handle<Context> context) {
11178 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011179 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011180
11181 // Allocate and initialize a JSObject with all the arguments, stack locals
11182 // heap locals and extension properties of the debugged function.
11183 Handle<JSObject> block_scope =
11184 isolate->factory()->NewJSObject(isolate->object_function());
11185
11186 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011187 if (!CopyContextLocalsToScopeObject(
11188 isolate, scope_info, context, block_scope)) {
11189 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011190 }
11191
11192 return block_scope;
11193}
11194
11195
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011196// Iterate over the actual scopes visible from a stack frame. The iteration
11197// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011198// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011199// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011200class ScopeIterator {
11201 public:
11202 enum ScopeType {
11203 ScopeTypeGlobal = 0,
11204 ScopeTypeLocal,
11205 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011206 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011207 ScopeTypeCatch,
11208 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011209 };
11210
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011211 ScopeIterator(Isolate* isolate,
11212 JavaScriptFrame* frame,
11213 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011214 : isolate_(isolate),
11215 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011216 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011217 function_(JSFunction::cast(frame->function())),
11218 context_(Context::cast(frame->context())),
erikcorry0ad885c2011-11-21 13:51:57 +000011219 local_done_(false),
11220 at_local_(false) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011221
erikcorry0ad885c2011-11-21 13:51:57 +000011222 // Check whether the first scope is actually a local scope.
11223 // If there is a stack slot for .result then this local scope has been
11224 // created for evaluating top level code and it is not a real local scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011225 // Checking for the existence of .result seems fragile, but the scope info
11226 // saved with the code object does not otherwise have that information.
erikcorry0ad885c2011-11-21 13:51:57 +000011227 int index = function_->shared()->scope_info()->
lrn@chromium.org34e60782011-09-15 07:25:40 +000011228 StackSlotIndex(isolate_->heap()->result_symbol());
11229 if (index >= 0) {
erikcorry0ad885c2011-11-21 13:51:57 +000011230 local_done_ = true;
11231 } else if (context_->IsGlobalContext() ||
11232 context_->IsFunctionContext()) {
11233 at_local_ = true;
11234 } else if (context_->closure() != *function_) {
11235 // The context_ is a block or with or catch block from the outer function.
11236 ASSERT(context_->IsWithContext() ||
11237 context_->IsCatchContext() ||
11238 context_->IsBlockContext());
11239 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011240 }
11241 }
11242
11243 // More scopes?
11244 bool Done() { return context_.is_null(); }
11245
11246 // Move to the next scope.
11247 void Next() {
erikcorry0ad885c2011-11-21 13:51:57 +000011248 // If at a local scope mark the local scope as passed.
11249 if (at_local_) {
11250 at_local_ = false;
11251 local_done_ = true;
11252
11253 // If the current context is not associated with the local scope the
11254 // current context is the next real scope, so don't move to the next
11255 // context in this case.
11256 if (context_->closure() != *function_) {
11257 return;
11258 }
11259 }
11260
11261 // The global scope is always the last in the chain.
11262 if (context_->IsGlobalContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011263 context_ = Handle<Context>();
11264 return;
11265 }
erikcorry0ad885c2011-11-21 13:51:57 +000011266
11267 // Move to the next context.
11268 context_ = Handle<Context>(context_->previous(), isolate_);
11269
11270 // If passing the local scope indicate that the current scope is now the
11271 // local scope.
11272 if (!local_done_ &&
11273 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
11274 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011275 }
11276 }
11277
11278 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011279 ScopeType Type() {
erikcorry0ad885c2011-11-21 13:51:57 +000011280 if (at_local_) {
11281 return ScopeTypeLocal;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011282 }
11283 if (context_->IsGlobalContext()) {
11284 ASSERT(context_->global()->IsGlobalObject());
11285 return ScopeTypeGlobal;
11286 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011287 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011288 return ScopeTypeClosure;
11289 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011290 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011291 return ScopeTypeCatch;
11292 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011293 if (context_->IsBlockContext()) {
11294 return ScopeTypeBlock;
11295 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011296 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011297 return ScopeTypeWith;
11298 }
11299
11300 // Return the JavaScript object with the content of the current scope.
11301 Handle<JSObject> ScopeObject() {
11302 switch (Type()) {
11303 case ScopeIterator::ScopeTypeGlobal:
11304 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011305 case ScopeIterator::ScopeTypeLocal:
11306 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011307 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011308 case ScopeIterator::ScopeTypeWith:
11309 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011310 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11311 case ScopeIterator::ScopeTypeCatch:
11312 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011313 case ScopeIterator::ScopeTypeClosure:
11314 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011315 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011316 case ScopeIterator::ScopeTypeBlock:
11317 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011318 }
11319 UNREACHABLE();
11320 return Handle<JSObject>();
11321 }
11322
11323 // Return the context for this scope. For the local context there might not
11324 // be an actual context.
11325 Handle<Context> CurrentContext() {
erikcorry0ad885c2011-11-21 13:51:57 +000011326 if (at_local_ && context_->closure() != *function_) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011327 return Handle<Context>();
11328 }
erikcorry0ad885c2011-11-21 13:51:57 +000011329 return context_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011330 }
11331
11332#ifdef DEBUG
11333 // Debug print of the content of the current scope.
11334 void DebugPrint() {
11335 switch (Type()) {
11336 case ScopeIterator::ScopeTypeGlobal:
11337 PrintF("Global:\n");
11338 CurrentContext()->Print();
11339 break;
11340
11341 case ScopeIterator::ScopeTypeLocal: {
11342 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011343 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011344 if (!CurrentContext().is_null()) {
11345 CurrentContext()->Print();
11346 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011347 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011348 if (extension->IsJSContextExtensionObject()) {
11349 extension->Print();
11350 }
11351 }
11352 }
11353 break;
11354 }
11355
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011356 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011357 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011358 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011359 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011360
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011361 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011362 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011363 CurrentContext()->extension()->Print();
11364 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011365 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011366
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011367 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011368 PrintF("Closure:\n");
11369 CurrentContext()->Print();
11370 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011371 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011372 if (extension->IsJSContextExtensionObject()) {
11373 extension->Print();
11374 }
11375 }
11376 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011377
11378 default:
11379 UNREACHABLE();
11380 }
11381 PrintF("\n");
11382 }
11383#endif
11384
11385 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011386 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011387 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011388 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011389 Handle<JSFunction> function_;
11390 Handle<Context> context_;
erikcorry0ad885c2011-11-21 13:51:57 +000011391 bool local_done_;
11392 bool at_local_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011393
11394 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11395};
11396
11397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011398RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011399 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011400 ASSERT(args.length() == 2);
11401
11402 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011403 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011404 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11405 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011406 if (!maybe_check->ToObject(&check)) return maybe_check;
11407 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011408 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11409
11410 // Get the frame where the debugging is performed.
11411 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011412 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011413 JavaScriptFrame* frame = it.frame();
11414
11415 // Count the visible scopes.
11416 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011417 for (ScopeIterator it(isolate, frame, 0);
11418 !it.Done();
11419 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011420 n++;
11421 }
11422
11423 return Smi::FromInt(n);
11424}
11425
11426
11427static const int kScopeDetailsTypeIndex = 0;
11428static const int kScopeDetailsObjectIndex = 1;
11429static const int kScopeDetailsSize = 2;
11430
11431// Return an array with scope details
11432// args[0]: number: break id
11433// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011434// args[2]: number: inlined frame index
11435// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011436//
11437// The array returned contains the following information:
11438// 0: Scope type
11439// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011440RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011441 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011442 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011443
11444 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011445 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011446 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11447 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011448 if (!maybe_check->ToObject(&check)) return maybe_check;
11449 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011450 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011451 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11452 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011453
11454 // Get the frame where the debugging is performed.
11455 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011456 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011457 JavaScriptFrame* frame = frame_it.frame();
11458
11459 // Find the requested scope.
11460 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011461 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011462 for (; !it.Done() && n < index; it.Next()) {
11463 n++;
11464 }
11465 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011466 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011467 }
11468
11469 // Calculate the size of the result.
11470 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011471 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011472
11473 // Fill in scope details.
11474 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011475 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011476 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011477 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011478
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011479 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011480}
11481
11482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011483RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011484 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011485 ASSERT(args.length() == 0);
11486
11487#ifdef DEBUG
11488 // Print the scopes for the top frame.
11489 StackFrameLocator locator;
11490 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011491 for (ScopeIterator it(isolate, frame, 0);
11492 !it.Done();
11493 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011494 it.DebugPrint();
11495 }
11496#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011497 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011498}
11499
11500
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011501RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011502 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011503 ASSERT(args.length() == 1);
11504
11505 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011506 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011507 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11508 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011509 if (!maybe_result->ToObject(&result)) return maybe_result;
11510 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011511
11512 // Count all archived V8 threads.
11513 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011514 for (ThreadState* thread =
11515 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011516 thread != NULL;
11517 thread = thread->Next()) {
11518 n++;
11519 }
11520
11521 // Total number of threads is current thread and archived threads.
11522 return Smi::FromInt(n + 1);
11523}
11524
11525
11526static const int kThreadDetailsCurrentThreadIndex = 0;
11527static const int kThreadDetailsThreadIdIndex = 1;
11528static const int kThreadDetailsSize = 2;
11529
11530// Return an array with thread details
11531// args[0]: number: break id
11532// args[1]: number: thread index
11533//
11534// The array returned contains the following information:
11535// 0: Is current thread?
11536// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011537RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011538 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011539 ASSERT(args.length() == 2);
11540
11541 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011542 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011543 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11544 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011545 if (!maybe_check->ToObject(&check)) return maybe_check;
11546 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011547 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11548
11549 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011550 Handle<FixedArray> details =
11551 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011552
11553 // Thread index 0 is current thread.
11554 if (index == 0) {
11555 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011556 details->set(kThreadDetailsCurrentThreadIndex,
11557 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011558 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011559 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011560 } else {
11561 // Find the thread with the requested index.
11562 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011563 ThreadState* thread =
11564 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011565 while (index != n && thread != NULL) {
11566 thread = thread->Next();
11567 n++;
11568 }
11569 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011570 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011571 }
11572
11573 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011574 details->set(kThreadDetailsCurrentThreadIndex,
11575 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011576 details->set(kThreadDetailsThreadIdIndex,
11577 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011578 }
11579
11580 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011581 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011582}
11583
11584
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011585// Sets the disable break state
11586// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011587RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011588 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011589 ASSERT(args.length() == 1);
11590 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011591 isolate->debug()->set_disable_break(disable_break);
11592 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011593}
11594
11595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011596RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011597 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011598 ASSERT(args.length() == 1);
11599
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011600 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11601 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011602 // Find the number of break points
11603 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011604 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011605 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011606 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011607 Handle<FixedArray>::cast(break_locations));
11608}
11609
11610
11611// Set a break point in a function
11612// args[0]: function
11613// args[1]: number: break source position (within the function source)
11614// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011615RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011616 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011617 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011618 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11619 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011620 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11621 RUNTIME_ASSERT(source_position >= 0);
11622 Handle<Object> break_point_object_arg = args.at<Object>(2);
11623
11624 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011625 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11626 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011627
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011628 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011629}
11630
11631
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011632Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11633 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011634 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011635 // Iterate the heap looking for SharedFunctionInfo generated from the
11636 // script. The inner most SharedFunctionInfo containing the source position
11637 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011638 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011639 // which is found is not compiled it is compiled and the heap is iterated
11640 // again as the compilation might create inner functions from the newly
11641 // compiled function and the actual requested break point might be in one of
11642 // these functions.
11643 bool done = false;
11644 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011645 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011646 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011647 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011648 { // Extra scope for iterator and no-allocation.
11649 isolate->heap()->EnsureHeapIsIterable();
11650 AssertNoAllocation no_alloc_during_heap_iteration;
11651 HeapIterator iterator;
11652 for (HeapObject* obj = iterator.next();
11653 obj != NULL; obj = iterator.next()) {
11654 if (obj->IsSharedFunctionInfo()) {
11655 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11656 if (shared->script() == *script) {
11657 // If the SharedFunctionInfo found has the requested script data and
11658 // contains the source position it is a candidate.
11659 int start_position = shared->function_token_position();
11660 if (start_position == RelocInfo::kNoPosition) {
11661 start_position = shared->start_position();
11662 }
11663 if (start_position <= position &&
11664 position <= shared->end_position()) {
11665 // If there is no candidate or this function is within the current
11666 // candidate this is the new candidate.
11667 if (target.is_null()) {
11668 target_start_position = start_position;
11669 target = shared;
11670 } else {
11671 if (target_start_position == start_position &&
11672 shared->end_position() == target->end_position()) {
11673 // If a top-level function contain only one function
11674 // declartion the source for the top-level and the
11675 // function is the same. In that case prefer the non
11676 // top-level function.
11677 if (!shared->is_toplevel()) {
11678 target_start_position = start_position;
11679 target = shared;
11680 }
11681 } else if (target_start_position <= start_position &&
11682 shared->end_position() <= target->end_position()) {
11683 // This containment check includes equality as a function
11684 // inside a top-level function can share either start or end
11685 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011686 target_start_position = start_position;
11687 target = shared;
11688 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011689 }
11690 }
11691 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011692 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011693 } // End for loop.
11694 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011695
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011696 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011697 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011698 }
11699
11700 // If the candidate found is compiled we are done. NOTE: when lazy
11701 // compilation of inner functions is introduced some additional checking
11702 // needs to be done here to compile inner functions.
11703 done = target->is_compiled();
11704 if (!done) {
11705 // If the candidate is not compiled compile it to reveal any inner
11706 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011707 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011708 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011709 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011710
11711 return *target;
11712}
11713
11714
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011715// Changes the state of a break point in a script and returns source position
11716// where break point was set. NOTE: Regarding performance see the NOTE for
11717// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011718// args[0]: script to set break point in
11719// args[1]: number: break source position (within the script source)
11720// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011721RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011722 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011723 ASSERT(args.length() == 3);
11724 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11725 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11726 RUNTIME_ASSERT(source_position >= 0);
11727 Handle<Object> break_point_object_arg = args.at<Object>(2);
11728
11729 // Get the script from the script wrapper.
11730 RUNTIME_ASSERT(wrapper->value()->IsScript());
11731 Handle<Script> script(Script::cast(wrapper->value()));
11732
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011733 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011734 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011735 if (!result->IsUndefined()) {
11736 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11737 // Find position within function. The script position might be before the
11738 // source position of the first function.
11739 int position;
11740 if (shared->start_position() > source_position) {
11741 position = 0;
11742 } else {
11743 position = source_position - shared->start_position();
11744 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011745 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011746 position += shared->start_position();
11747 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011748 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011749 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011750}
11751
11752
11753// Clear a break point
11754// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011755RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011756 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011757 ASSERT(args.length() == 1);
11758 Handle<Object> break_point_object_arg = args.at<Object>(0);
11759
11760 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011761 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011762
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011763 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011764}
11765
11766
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011767// Change the state of break on exceptions.
11768// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11769// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011770RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011771 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011772 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011773 RUNTIME_ASSERT(args[0]->IsNumber());
11774 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011775
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011776 // If the number doesn't match an enum value, the ChangeBreakOnException
11777 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011778 ExceptionBreakType type =
11779 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011780 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011781 isolate->debug()->ChangeBreakOnException(type, enable);
11782 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011783}
11784
11785
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011786// Returns the state of break on exceptions
11787// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011788RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011789 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011790 ASSERT(args.length() == 1);
11791 RUNTIME_ASSERT(args[0]->IsNumber());
11792
11793 ExceptionBreakType type =
11794 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011795 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011796 return Smi::FromInt(result);
11797}
11798
11799
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011800// Prepare for stepping
11801// args[0]: break id for checking execution state
11802// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011803// args[2]: number of times to perform the step, for step out it is the number
11804// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011805RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011806 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011807 ASSERT(args.length() == 3);
11808 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011809 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011810 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11811 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011812 if (!maybe_check->ToObject(&check)) return maybe_check;
11813 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011814 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011815 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011816 }
11817
11818 // Get the step action and check validity.
11819 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11820 if (step_action != StepIn &&
11821 step_action != StepNext &&
11822 step_action != StepOut &&
11823 step_action != StepInMin &&
11824 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011825 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011826 }
11827
11828 // Get the number of steps.
11829 int step_count = NumberToInt32(args[2]);
11830 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011831 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011832 }
11833
ager@chromium.orga1645e22009-09-09 19:27:10 +000011834 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011835 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011836
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011837 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011838 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11839 step_count);
11840 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011841}
11842
11843
11844// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011845RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011846 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011847 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011848 isolate->debug()->ClearStepping();
11849 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011850}
11851
11852
11853// Creates a copy of the with context chain. The copy of the context chain is
11854// is linked to the function context supplied.
erikcorry0ad885c2011-11-21 13:51:57 +000011855static Handle<Context> CopyWithContextChain(Isolate* isolate,
11856 Handle<JSFunction> function,
11857 Handle<Context> current,
11858 Handle<Context> base) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011859 // At the end of the chain. Return the base context to link to.
erikcorry0ad885c2011-11-21 13:51:57 +000011860 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11861 return base;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011862 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011863
erikcorry0ad885c2011-11-21 13:51:57 +000011864 // Recursively copy the with and catch contexts.
11865 HandleScope scope(isolate);
11866 Handle<Context> previous(current->previous());
11867 Handle<Context> new_previous =
11868 CopyWithContextChain(isolate, function, previous, base);
11869 Handle<Context> new_current;
11870 if (current->IsCatchContext()) {
11871 Handle<String> name(String::cast(current->extension()));
11872 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11873 new_current =
11874 isolate->factory()->NewCatchContext(function,
11875 new_previous,
11876 name,
11877 thrown_object);
11878 } else if (current->IsBlockContext()) {
11879 Handle<ScopeInfo> scope_info(ScopeInfo::cast(current->extension()));
11880 new_current =
11881 isolate->factory()->NewBlockContext(function, new_previous, scope_info);
11882 // Copy context slots.
11883 int num_context_slots = scope_info->ContextLength();
11884 for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
11885 new_current->set(i, current->get(i));
11886 }
11887 } else {
11888 ASSERT(current->IsWithContext());
11889 Handle<JSObject> extension(JSObject::cast(current->extension()));
11890 new_current =
11891 isolate->factory()->NewWithContext(function, new_previous, extension);
11892 }
11893 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011894}
11895
11896
11897// Helper function to find or create the arguments object for
11898// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011899static Handle<Object> GetArgumentsObject(Isolate* isolate,
11900 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011901 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011902 Handle<JSFunction> function,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011903 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011904 Handle<Context> function_context) {
11905 // Try to find the value of 'arguments' to pass as parameter. If it is not
11906 // found (that is the debugged function does not reference 'arguments' and
11907 // does not support eval) then create an 'arguments' object.
11908 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011909 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011910 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011911 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011912 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011913 }
11914 }
11915
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011916 if (scope_info->HasHeapAllocatedLocals()) {
11917 VariableMode mode;
11918 InitializationFlag init_flag;
11919 index = scope_info->ContextSlotIndex(
11920 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011921 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011922 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011923 }
11924 }
11925
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011926 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11927
11928 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011929 Handle<JSObject> arguments =
11930 isolate->factory()->NewArgumentsObject(function, length);
11931 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011932
11933 AssertNoAllocation no_gc;
11934 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011935 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011936 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011937 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011938 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011939 return arguments;
11940}
11941
11942
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011943static const char kSourceStr[] =
11944 "(function(arguments,__source__){return eval(__source__);})";
11945
11946
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011947// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011948// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011949// extension part has all the parameters and locals of the function on the
11950// stack frame. A function which calls eval with the code to evaluate is then
11951// compiled in this context and called in this context. As this context
11952// replaces the context of the function on the stack frame a new (empty)
11953// function is created as well to be used as the closure for the context.
11954// This function and the context acts as replacements for the function on the
11955// stack frame presenting the same view of the values of parameters and
11956// local variables as if the piece of JavaScript was evaluated at the point
11957// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011958RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011959 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011960
11961 // Check the execution state and decode arguments frame and source to be
11962 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011963 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011964 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011965 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11966 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011967 if (!maybe_check_result->ToObject(&check_result)) {
11968 return maybe_check_result;
11969 }
11970 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011971 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011972 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11973 CONVERT_ARG_CHECKED(String, source, 3);
11974 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11975 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011976
11977 // Handle the processing of break.
11978 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011979
11980 // Get the frame where the debugging is performed.
11981 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011982 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011983 JavaScriptFrame* frame = it.frame();
11984 Handle<JSFunction> function(JSFunction::cast(frame->function()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011985 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011986
11987 // Traverse the saved contexts chain to find the active context for the
11988 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011989 SaveContext* save = FindSavedContextForFrame(isolate, frame);
11990
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011991 SaveContext savex(isolate);
11992 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011993
11994 // Create the (empty) function replacing the function on the stack frame for
11995 // the purpose of evaluating in the context created below. It is important
11996 // that this function does not describe any parameters and local variables
11997 // in the context. If it does then this will cause problems with the lookup
11998 // in Context::Lookup, where context slots for parameters and local variables
11999 // are looked at before the extension object.
12000 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012001 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12002 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012003 go_between->set_context(function->context());
12004#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012005 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12006 ASSERT(go_between_scope_info->ParameterCount() == 0);
12007 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012008#endif
12009
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012010 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012011 Handle<JSObject> local_scope = MaterializeLocalScope(
12012 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012013 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012014
12015 // Allocate a new context for the debug evaluation and set the extension
12016 // object build.
12017 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012018 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12019 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012020 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012021 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012022 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012023 Handle<Context> function_context;
12024 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012025 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012026 function_context = Handle<Context>(frame_context->declaration_context());
12027 }
erikcorry0ad885c2011-11-21 13:51:57 +000012028 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012029
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012030 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012031 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012032 context =
12033 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012034 }
12035
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012036 // Wrap the evaluation statement in a new function compiled in the newly
12037 // created context. The function has one parameter which has to be called
12038 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012039 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012040 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012041
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012042 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012043 isolate->factory()->NewStringFromAscii(
12044 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012045
12046 // Currently, the eval code will be executed in non-strict mode,
12047 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012048 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012049 Compiler::CompileEval(function_source,
12050 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012051 context->IsGlobalContext(),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012052 kNonStrictMode,
12053 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012054 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012055 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012056 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012057
12058 // Invoke the result of the compilation to get the evaluation function.
12059 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012060 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012061 Handle<Object> evaluation_function =
12062 Execution::Call(compiled_function, receiver, 0, NULL,
12063 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012064 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012065
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012066 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012067 frame,
12068 inlined_frame_index,
12069 function,
12070 scope_info,
12071 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012072
12073 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012074 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012075 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012076 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12077 receiver,
12078 ARRAY_SIZE(argv),
12079 argv,
12080 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012081 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012082
12083 // Skip the global proxy as it has no properties and always delegates to the
12084 // real global object.
12085 if (result->IsJSGlobalProxy()) {
12086 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12087 }
12088
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012089 return *result;
12090}
12091
12092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012093RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012094 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012095
12096 // Check the execution state and decode arguments frame and source to be
12097 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012098 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012099 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012100 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12101 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012102 if (!maybe_check_result->ToObject(&check_result)) {
12103 return maybe_check_result;
12104 }
12105 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012106 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012107 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012108 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012109
12110 // Handle the processing of break.
12111 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012112
12113 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012114 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012115 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012116 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012117 top = top->prev();
12118 }
12119 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012120 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012121 }
12122
12123 // Get the global context now set to the top context from before the
12124 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012125 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012126
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012127 bool is_global = true;
12128
12129 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012130 // Create a new with context with the additional context information between
12131 // the context of the debugged function and the eval code to be executed.
12132 context = isolate->factory()->NewWithContext(
12133 Handle<JSFunction>(context->closure()),
12134 context,
12135 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012136 is_global = false;
12137 }
12138
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012139 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012140 // Currently, the eval code will be executed in non-strict mode,
12141 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012142 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012143 Compiler::CompileEval(source,
12144 context,
12145 is_global,
12146 kNonStrictMode,
12147 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012148 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012149 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012150 Handle<JSFunction>(
12151 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12152 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012153
12154 // Invoke the result of the compilation to get the evaluation function.
12155 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012156 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012157 Handle<Object> result =
12158 Execution::Call(compiled_function, receiver, 0, NULL,
12159 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012160 // Clear the oneshot breakpoints so that the debugger does not step further.
12161 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012162 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012163 return *result;
12164}
12165
12166
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012167RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012168 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012169 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012170
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012171 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012172 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012173
12174 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012175 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012176 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12177 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12178 // because using
12179 // instances->set(i, *GetScriptWrapper(script))
12180 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
12181 // already have deferenced the instances handle.
12182 Handle<JSValue> wrapper = GetScriptWrapper(script);
12183 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012184 }
12185
12186 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012187 Handle<JSObject> result =
12188 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012189 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012190 return *result;
12191}
12192
12193
12194// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012195static int DebugReferencedBy(HeapIterator* iterator,
12196 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012197 Object* instance_filter, int max_references,
12198 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012199 JSFunction* arguments_function) {
12200 NoHandleAllocation ha;
12201 AssertNoAllocation no_alloc;
12202
12203 // Iterate the heap.
12204 int count = 0;
12205 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012206 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012207 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012208 (max_references == 0 || count < max_references)) {
12209 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012210 if (heap_obj->IsJSObject()) {
12211 // Skip context extension objects and argument arrays as these are
12212 // checked in the context of functions using them.
12213 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012214 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012215 obj->map()->constructor() == arguments_function) {
12216 continue;
12217 }
12218
12219 // Check if the JS object has a reference to the object looked for.
12220 if (obj->ReferencesObject(target)) {
12221 // Check instance filter if supplied. This is normally used to avoid
12222 // references from mirror objects (see Runtime_IsInPrototypeChain).
12223 if (!instance_filter->IsUndefined()) {
12224 Object* V = obj;
12225 while (true) {
12226 Object* prototype = V->GetPrototype();
12227 if (prototype->IsNull()) {
12228 break;
12229 }
12230 if (instance_filter == prototype) {
12231 obj = NULL; // Don't add this object.
12232 break;
12233 }
12234 V = prototype;
12235 }
12236 }
12237
12238 if (obj != NULL) {
12239 // Valid reference found add to instance array if supplied an update
12240 // count.
12241 if (instances != NULL && count < instances_size) {
12242 instances->set(count, obj);
12243 }
12244 last = obj;
12245 count++;
12246 }
12247 }
12248 }
12249 }
12250
12251 // Check for circular reference only. This can happen when the object is only
12252 // referenced from mirrors and has a circular reference in which case the
12253 // object is not really alive and would have been garbage collected if not
12254 // referenced from the mirror.
12255 if (count == 1 && last == target) {
12256 count = 0;
12257 }
12258
12259 // Return the number of referencing objects found.
12260 return count;
12261}
12262
12263
12264// Scan the heap for objects with direct references to an object
12265// args[0]: the object to find references to
12266// args[1]: constructor function for instances to exclude (Mirror)
12267// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012268RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012269 ASSERT(args.length() == 3);
12270
12271 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012272 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12273 // The heap iterator reserves the right to do a GC to make the heap iterable.
12274 // Due to the GC above we know it won't need to do that, but it seems cleaner
12275 // to get the heap iterator constructed before we start having unprotected
12276 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012277
12278 // Check parameters.
12279 CONVERT_CHECKED(JSObject, target, args[0]);
12280 Object* instance_filter = args[1];
12281 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12282 instance_filter->IsJSObject());
12283 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12284 RUNTIME_ASSERT(max_references >= 0);
12285
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012286
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012287 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012288 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012289 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012290 JSFunction* arguments_function =
12291 JSFunction::cast(arguments_boilerplate->map()->constructor());
12292
12293 // Get the number of referencing objects.
12294 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012295 HeapIterator heap_iterator;
12296 count = DebugReferencedBy(&heap_iterator,
12297 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012298 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012299
12300 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012301 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012302 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012303 if (!maybe_object->ToObject(&object)) return maybe_object;
12304 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012305 FixedArray* instances = FixedArray::cast(object);
12306
12307 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012308 // AllocateFixedArray above does not make the heap non-iterable.
12309 ASSERT(HEAP->IsHeapIterable());
12310 HeapIterator heap_iterator2;
12311 count = DebugReferencedBy(&heap_iterator2,
12312 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012313 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012314
12315 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012316 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012317 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012318 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012319 if (!maybe_result->ToObject(&result)) return maybe_result;
12320 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012321}
12322
12323
12324// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012325static int DebugConstructedBy(HeapIterator* iterator,
12326 JSFunction* constructor,
12327 int max_references,
12328 FixedArray* instances,
12329 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012330 AssertNoAllocation no_alloc;
12331
12332 // Iterate the heap.
12333 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012334 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012335 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012336 (max_references == 0 || count < max_references)) {
12337 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012338 if (heap_obj->IsJSObject()) {
12339 JSObject* obj = JSObject::cast(heap_obj);
12340 if (obj->map()->constructor() == constructor) {
12341 // Valid reference found add to instance array if supplied an update
12342 // count.
12343 if (instances != NULL && count < instances_size) {
12344 instances->set(count, obj);
12345 }
12346 count++;
12347 }
12348 }
12349 }
12350
12351 // Return the number of referencing objects found.
12352 return count;
12353}
12354
12355
12356// Scan the heap for objects constructed by a specific function.
12357// args[0]: the constructor to find instances of
12358// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012359RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012360 ASSERT(args.length() == 2);
12361
12362 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012363 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012364
12365 // Check parameters.
12366 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12367 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12368 RUNTIME_ASSERT(max_references >= 0);
12369
12370 // Get the number of referencing objects.
12371 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012372 HeapIterator heap_iterator;
12373 count = DebugConstructedBy(&heap_iterator,
12374 constructor,
12375 max_references,
12376 NULL,
12377 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012378
12379 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012380 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012381 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012382 if (!maybe_object->ToObject(&object)) return maybe_object;
12383 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012384 FixedArray* instances = FixedArray::cast(object);
12385
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012386 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012387 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012388 HeapIterator heap_iterator2;
12389 count = DebugConstructedBy(&heap_iterator2,
12390 constructor,
12391 max_references,
12392 instances,
12393 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012394
12395 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012396 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012397 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12398 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012399 if (!maybe_result->ToObject(&result)) return maybe_result;
12400 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012401 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012402}
12403
12404
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012405// Find the effective prototype object as returned by __proto__.
12406// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012407RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012408 ASSERT(args.length() == 1);
12409
12410 CONVERT_CHECKED(JSObject, obj, args[0]);
12411
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012412 // Use the __proto__ accessor.
12413 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012414}
12415
12416
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012417RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012418 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012419 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012420 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012421}
12422
12423
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012424RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012425#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012426 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012427 ASSERT(args.length() == 1);
12428 // Get the function and make sure it is compiled.
12429 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012430 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012431 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012432 return Failure::Exception();
12433 }
12434 func->code()->PrintLn();
12435#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012436 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012437}
ager@chromium.org9085a012009-05-11 19:22:57 +000012438
12439
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012440RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012441#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012442 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012443 ASSERT(args.length() == 1);
12444 // Get the function and make sure it is compiled.
12445 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012446 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012447 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012448 return Failure::Exception();
12449 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012450 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012451#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012452 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012453}
12454
12455
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012456RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012457 NoHandleAllocation ha;
12458 ASSERT(args.length() == 1);
12459
12460 CONVERT_CHECKED(JSFunction, f, args[0]);
12461 return f->shared()->inferred_name();
12462}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012463
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012464
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012465static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12466 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012467 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012468 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012469 int counter = 0;
12470 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012471 for (HeapObject* obj = iterator->next();
12472 obj != NULL;
12473 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012474 ASSERT(obj != NULL);
12475 if (!obj->IsSharedFunctionInfo()) {
12476 continue;
12477 }
12478 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12479 if (shared->script() != script) {
12480 continue;
12481 }
12482 if (counter < buffer_size) {
12483 buffer->set(counter, shared);
12484 }
12485 counter++;
12486 }
12487 return counter;
12488}
12489
12490// For a script finds all SharedFunctionInfo's in the heap that points
12491// to this script. Returns JSArray of SharedFunctionInfo wrapped
12492// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012493RUNTIME_FUNCTION(MaybeObject*,
12494 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012495 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012496 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012497 CONVERT_CHECKED(JSValue, script_value, args[0]);
12498
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012499
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012500 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12501
12502 const int kBufferSize = 32;
12503
12504 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012505 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012506 int number;
12507 {
12508 isolate->heap()->EnsureHeapIsIterable();
12509 AssertNoAllocation no_allocations;
12510 HeapIterator heap_iterator;
12511 Script* scr = *script;
12512 FixedArray* arr = *array;
12513 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12514 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012515 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012516 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012517 isolate->heap()->EnsureHeapIsIterable();
12518 AssertNoAllocation no_allocations;
12519 HeapIterator heap_iterator;
12520 Script* scr = *script;
12521 FixedArray* arr = *array;
12522 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012523 }
12524
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012525 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012526 result->set_length(Smi::FromInt(number));
12527
12528 LiveEdit::WrapSharedFunctionInfos(result);
12529
12530 return *result;
12531}
12532
12533// For a script calculates compilation information about all its functions.
12534// The script source is explicitly specified by the second argument.
12535// The source of the actual script is not used, however it is important that
12536// all generated code keeps references to this particular instance of script.
12537// Returns a JSArray of compilation infos. The array is ordered so that
12538// each function with all its descendant is always stored in a continues range
12539// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012540RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012541 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012542 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012543 CONVERT_CHECKED(JSValue, script, args[0]);
12544 CONVERT_ARG_CHECKED(String, source, 1);
12545 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12546
12547 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12548
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012549 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012550 return Failure::Exception();
12551 }
12552
12553 return result;
12554}
12555
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012556// Changes the source of the script to a new_source.
12557// If old_script_name is provided (i.e. is a String), also creates a copy of
12558// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012559RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012560 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012561 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012562 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12563 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012564 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012565
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012566 CONVERT_CHECKED(Script, original_script_pointer,
12567 original_script_value->value());
12568 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012569
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012570 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12571 new_source,
12572 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012573
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012574 if (old_script->IsScript()) {
12575 Handle<Script> script_handle(Script::cast(old_script));
12576 return *(GetScriptWrapper(script_handle));
12577 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012578 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012579 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012580}
12581
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012583RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012584 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012585 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012586 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12587 return LiveEdit::FunctionSourceUpdated(shared_info);
12588}
12589
12590
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012591// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012592RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012593 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012594 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012595 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12596 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12597
ager@chromium.orgac091b72010-05-05 07:34:42 +000012598 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012599}
12600
12601// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012602RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012603 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012604 HandleScope scope(isolate);
12605 Handle<Object> function_object(args[0], isolate);
12606 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012607
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012608 if (function_object->IsJSValue()) {
12609 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12610 if (script_object->IsJSValue()) {
12611 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012612 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012613 }
12614
12615 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12616 } else {
12617 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12618 // and we check it in this function.
12619 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012620
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012621 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012622}
12623
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012624
12625// In a code of a parent function replaces original function as embedded object
12626// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012627RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012628 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012629 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012630
12631 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12632 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12633 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12634
12635 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12636 subst_wrapper);
12637
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012638 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012639}
12640
12641
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012642// Updates positions of a shared function info (first parameter) according
12643// to script source change. Text change is described in second parameter as
12644// array of groups of 3 numbers:
12645// (change_begin, change_end, change_end_new_position).
12646// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012647RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012648 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012649 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012650 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12651 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12652
ager@chromium.orgac091b72010-05-05 07:34:42 +000012653 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012654}
12655
12656
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012657// For array of SharedFunctionInfo's (each wrapped in JSValue)
12658// checks that none of them have activations on stacks (of any thread).
12659// Returns array of the same length with corresponding results of
12660// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012661RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012662 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012663 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012664 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012665 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012666
ager@chromium.org357bf652010-04-12 11:30:10 +000012667 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012668}
12669
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012670// Compares 2 strings line-by-line, then token-wise and returns diff in form
12671// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12672// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012673RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012674 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012675 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012676 CONVERT_ARG_CHECKED(String, s1, 0);
12677 CONVERT_ARG_CHECKED(String, s2, 1);
12678
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012679 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012680}
12681
12682
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012683// A testing entry. Returns statement position which is the closest to
12684// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012685RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012686 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012687 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012688 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12689 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12690
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012691 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012692
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012693 if (code->kind() != Code::FUNCTION &&
12694 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012695 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012696 }
12697
12698 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012699 int closest_pc = 0;
12700 int distance = kMaxInt;
12701 while (!it.done()) {
12702 int statement_position = static_cast<int>(it.rinfo()->data());
12703 // Check if this break point is closer that what was previously found.
12704 if (source_position <= statement_position &&
12705 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012706 closest_pc =
12707 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012708 distance = statement_position - source_position;
12709 // Check whether we can't get any closer.
12710 if (distance == 0) break;
12711 }
12712 it.next();
12713 }
12714
12715 return Smi::FromInt(closest_pc);
12716}
12717
12718
ager@chromium.org357bf652010-04-12 11:30:10 +000012719// Calls specified function with or without entering the debugger.
12720// This is used in unit tests to run code as if debugger is entered or simply
12721// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012722RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012723 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012724 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012725 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12726 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12727
12728 Handle<Object> result;
12729 bool pending_exception;
12730 {
12731 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012732 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012733 &pending_exception);
12734 } else {
12735 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012736 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012737 &pending_exception);
12738 }
12739 }
12740 if (!pending_exception) {
12741 return *result;
12742 } else {
12743 return Failure::Exception();
12744 }
12745}
12746
12747
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012748// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012749RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012750 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012751 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012752 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12753 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012754 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012755}
12756
12757
12758// Performs a GC.
12759// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012760RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012761 isolate->heap()->CollectAllGarbage(true);
12762 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012763}
12764
12765
12766// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012767RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012768 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012769 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012770 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012771 }
12772 return Smi::FromInt(usage);
12773}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012774
12775
12776// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012777RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012778#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012779 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012780#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012781 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012782#endif
12783}
12784
12785
12786// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012787RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012788#ifdef LIVE_OBJECT_LIST
12789 return LiveObjectList::Capture();
12790#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012791 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012792#endif
12793}
12794
12795
12796// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012797RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012798#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012799 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012800 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012801 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012802#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012803 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012804#endif
12805}
12806
12807
12808// Generates the response to a debugger request for a dump of the objects
12809// contained in the difference between the captured live object lists
12810// specified by id1 and id2.
12811// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12812// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012813RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012814#ifdef LIVE_OBJECT_LIST
12815 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012816 CONVERT_SMI_ARG_CHECKED(id1, 0);
12817 CONVERT_SMI_ARG_CHECKED(id2, 1);
12818 CONVERT_SMI_ARG_CHECKED(start, 2);
12819 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012820 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12821 EnterDebugger enter_debugger;
12822 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12823#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012824 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012825#endif
12826}
12827
12828
12829// Gets the specified object as requested by the debugger.
12830// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012831RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012832#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012833 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012834 Object* result = LiveObjectList::GetObj(obj_id);
12835 return result;
12836#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012837 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012838#endif
12839}
12840
12841
12842// Gets the obj id for the specified address if valid.
12843// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012844RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012845#ifdef LIVE_OBJECT_LIST
12846 HandleScope scope;
12847 CONVERT_ARG_CHECKED(String, address, 0);
12848 Object* result = LiveObjectList::GetObjId(address);
12849 return result;
12850#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012851 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012852#endif
12853}
12854
12855
12856// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012857RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012858#ifdef LIVE_OBJECT_LIST
12859 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012860 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012861 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12862 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12863 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12864 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12865 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12866
12867 Handle<JSObject> instance_filter;
12868 if (args[1]->IsJSObject()) {
12869 instance_filter = args.at<JSObject>(1);
12870 }
12871 bool verbose = false;
12872 if (args[2]->IsBoolean()) {
12873 verbose = args[2]->IsTrue();
12874 }
12875 int start = 0;
12876 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012877 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012878 }
12879 int limit = Smi::kMaxValue;
12880 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012881 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012882 }
12883
12884 return LiveObjectList::GetObjRetainers(obj_id,
12885 instance_filter,
12886 verbose,
12887 start,
12888 limit,
12889 filter_obj);
12890#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012891 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012892#endif
12893}
12894
12895
12896// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012897RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012898#ifdef LIVE_OBJECT_LIST
12899 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012900 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12901 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012902 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12903
12904 Handle<JSObject> instance_filter;
12905 if (args[2]->IsJSObject()) {
12906 instance_filter = args.at<JSObject>(2);
12907 }
12908
12909 Object* result =
12910 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12911 return result;
12912#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012913 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012914#endif
12915}
12916
12917
12918// Generates the response to a debugger request for a list of all
12919// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012920RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012921#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012922 CONVERT_SMI_ARG_CHECKED(start, 0);
12923 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012924 return LiveObjectList::Info(start, count);
12925#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012926 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012927#endif
12928}
12929
12930
12931// Gets a dump of the specified object as requested by the debugger.
12932// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012933RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012934#ifdef LIVE_OBJECT_LIST
12935 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012936 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012937 Object* result = LiveObjectList::PrintObj(obj_id);
12938 return result;
12939#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012940 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012941#endif
12942}
12943
12944
12945// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012946RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012947#ifdef LIVE_OBJECT_LIST
12948 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012949 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012950#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012951 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012952#endif
12953}
12954
12955
12956// Generates the response to a debugger request for a summary of the types
12957// of objects in the difference between the captured live object lists
12958// specified by id1 and id2.
12959// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12960// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012961RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012962#ifdef LIVE_OBJECT_LIST
12963 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012964 CONVERT_SMI_ARG_CHECKED(id1, 0);
12965 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012966 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12967
12968 EnterDebugger enter_debugger;
12969 return LiveObjectList::Summarize(id1, id2, filter_obj);
12970#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012971 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012972#endif
12973}
12974
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012975#endif // ENABLE_DEBUGGER_SUPPORT
12976
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012978RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012979 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012980 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012981 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012982}
12983
12984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012985RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012986 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012987 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012988 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012989}
12990
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012991
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012992// Finds the script object from the script data. NOTE: This operation uses
12993// heap traversal to find the function generated for the source position
12994// for the requested break point. For lazily compiled functions several heap
12995// traversals might be required rendering this operation as a rather slow
12996// operation. However for setting break points which is normally done through
12997// some kind of user interaction the performance is not crucial.
12998static Handle<Object> Runtime_GetScriptFromScriptName(
12999 Handle<String> script_name) {
13000 // Scan the heap for Script objects to find the script with the requested
13001 // script data.
13002 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013003 script_name->GetHeap()->EnsureHeapIsIterable();
13004 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013005 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013006 HeapObject* obj = NULL;
13007 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013008 // If a script is found check if it has the script data requested.
13009 if (obj->IsScript()) {
13010 if (Script::cast(obj)->name()->IsString()) {
13011 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13012 script = Handle<Script>(Script::cast(obj));
13013 }
13014 }
13015 }
13016 }
13017
13018 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013019 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013020
13021 // Return the script found.
13022 return GetScriptWrapper(script);
13023}
13024
13025
13026// Get the script object from script data. NOTE: Regarding performance
13027// see the NOTE for GetScriptFromScriptData.
13028// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013029RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013030 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013031
13032 ASSERT(args.length() == 1);
13033
13034 CONVERT_CHECKED(String, script_name, args[0]);
13035
13036 // Find the requested script.
13037 Handle<Object> result =
13038 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13039 return *result;
13040}
13041
13042
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013043// Determines whether the given stack frame should be displayed in
13044// a stack trace. The caller is the error constructor that asked
13045// for the stack trace to be collected. The first time a construct
13046// call to this function is encountered it is skipped. The seen_caller
13047// in/out parameter is used to remember if the caller has been seen
13048// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013049static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13050 Object* caller,
13051 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013052 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013053 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013054 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013055 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013056 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13057 Object* raw_fun = frame->function();
13058 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013059 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013060 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013061 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013062 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013063 *seen_caller = true;
13064 return false;
13065 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013066 // Skip all frames until we've seen the caller.
13067 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013068 // Also, skip non-visible built-in functions and any call with the builtins
13069 // object as receiver, so as to not reveal either the builtins object or
13070 // an internal function.
13071 // The --builtins-in-stack-traces command line flag allows including
13072 // internal call sites in the stack trace for debugging purposes.
13073 if (!FLAG_builtins_in_stack_traces) {
13074 JSFunction* fun = JSFunction::cast(raw_fun);
13075 if (frame->receiver()->IsJSBuiltinsObject() ||
13076 (fun->IsBuiltin() && !fun->shared()->native())) {
13077 return false;
13078 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013079 }
13080 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013081}
13082
13083
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013084// Collect the raw data for a stack trace. Returns an array of 4
13085// element segments each containing a receiver, function, code and
13086// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013087RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013088 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013089 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013090 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
13091
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013092 HandleScope scope(isolate);
13093 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013094
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013095 limit = Max(limit, 0); // Ensure that limit is not negative.
13096 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013097 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013098 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013099
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013100 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013101 // If the caller parameter is a function we skip frames until we're
13102 // under it before starting to collect.
13103 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013104 int cursor = 0;
13105 int frames_seen = 0;
13106 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013107 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013108 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013109 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013110 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013111 // Set initial size to the maximum inlining level + 1 for the outermost
13112 // function.
13113 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013114 frame->Summarize(&frames);
13115 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013116 if (cursor + 4 > elements->length()) {
13117 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13118 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013119 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013120 for (int i = 0; i < cursor; i++) {
13121 new_elements->set(i, elements->get(i));
13122 }
13123 elements = new_elements;
13124 }
13125 ASSERT(cursor + 4 <= elements->length());
13126
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013127 Handle<Object> recv = frames[i].receiver();
13128 Handle<JSFunction> fun = frames[i].function();
13129 Handle<Code> code = frames[i].code();
13130 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013131 elements->set(cursor++, *recv);
13132 elements->set(cursor++, *fun);
13133 elements->set(cursor++, *code);
13134 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013135 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013136 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013137 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013138 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013139 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013140 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013141 return *result;
13142}
13143
13144
ager@chromium.org3811b432009-10-28 14:53:37 +000013145// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013146RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013147 ASSERT_EQ(args.length(), 0);
13148
13149 NoHandleAllocation ha;
13150
13151 const char* version_string = v8::V8::GetVersion();
13152
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013153 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13154 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013155}
13156
13157
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013158RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013159 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013160 OS::PrintError("abort: %s\n",
13161 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013162 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013163 OS::Abort();
13164 UNREACHABLE();
13165 return NULL;
13166}
13167
13168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013169RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013170 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013171 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013172 Object* key = args[1];
13173
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013174 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013175 Object* o = cache->get(finger_index);
13176 if (o == key) {
13177 // The fastest case: hit the same place again.
13178 return cache->get(finger_index + 1);
13179 }
13180
13181 for (int i = finger_index - 2;
13182 i >= JSFunctionResultCache::kEntriesIndex;
13183 i -= 2) {
13184 o = cache->get(i);
13185 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013186 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013187 return cache->get(i + 1);
13188 }
13189 }
13190
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013191 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013192 ASSERT(size <= cache->length());
13193
13194 for (int i = size - 2; i > finger_index; i -= 2) {
13195 o = cache->get(i);
13196 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013197 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013198 return cache->get(i + 1);
13199 }
13200 }
13201
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013202 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013203 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013204
13205 Handle<JSFunctionResultCache> cache_handle(cache);
13206 Handle<Object> key_handle(key);
13207 Handle<Object> value;
13208 {
13209 Handle<JSFunction> factory(JSFunction::cast(
13210 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13211 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013212 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013213 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013214 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013215 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013216 value = Execution::Call(factory,
13217 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013218 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013219 argv,
13220 &pending_exception);
13221 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013222 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013223
13224#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013225 if (FLAG_verify_heap) {
13226 cache_handle->JSFunctionResultCacheVerify();
13227 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013228#endif
13229
13230 // Function invocation may have cleared the cache. Reread all the data.
13231 finger_index = cache_handle->finger_index();
13232 size = cache_handle->size();
13233
13234 // If we have spare room, put new data into it, otherwise evict post finger
13235 // entry which is likely to be the least recently used.
13236 int index = -1;
13237 if (size < cache_handle->length()) {
13238 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13239 index = size;
13240 } else {
13241 index = finger_index + JSFunctionResultCache::kEntrySize;
13242 if (index == cache_handle->length()) {
13243 index = JSFunctionResultCache::kEntriesIndex;
13244 }
13245 }
13246
13247 ASSERT(index % 2 == 0);
13248 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13249 ASSERT(index < cache_handle->length());
13250
13251 cache_handle->set(index, *key_handle);
13252 cache_handle->set(index + 1, *value);
13253 cache_handle->set_finger_index(index);
13254
13255#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013256 if (FLAG_verify_heap) {
13257 cache_handle->JSFunctionResultCacheVerify();
13258 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013259#endif
13260
13261 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013262}
13263
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013265RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013266 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013267 CONVERT_ARG_CHECKED(String, type, 0);
13268 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013269 return *isolate->factory()->NewJSMessageObject(
13270 type,
13271 arguments,
13272 0,
13273 0,
13274 isolate->factory()->undefined_value(),
13275 isolate->factory()->undefined_value(),
13276 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013277}
13278
13279
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013280RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013281 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13282 return message->type();
13283}
13284
13285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013286RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013287 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13288 return message->arguments();
13289}
13290
13291
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013292RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013293 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13294 return Smi::FromInt(message->start_position());
13295}
13296
13297
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013298RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013299 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13300 return message->script();
13301}
13302
13303
kasper.lund44510672008-07-25 07:37:58 +000013304#ifdef DEBUG
13305// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13306// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013307RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013308 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013309 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013310#define COUNT_ENTRY(Name, argc, ressize) + 1
13311 int entry_count = 0
13312 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13313 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13314 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13315#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013316 Factory* factory = isolate->factory();
13317 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013318 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013319 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013320#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013321 { \
13322 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013323 Handle<String> name; \
13324 /* Inline runtime functions have an underscore in front of the name. */ \
13325 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013326 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013327 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13328 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013329 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013330 Vector<const char>(#Name, StrLength(#Name))); \
13331 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013332 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013333 pair_elements->set(0, *name); \
13334 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013335 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013336 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013337 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013338 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013339 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013340 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013341 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013342 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013343#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013344 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013345 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013346 return *result;
13347}
kasper.lund44510672008-07-25 07:37:58 +000013348#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013349
13350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013351RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013352 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013353 CONVERT_CHECKED(String, format, args[0]);
13354 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013355 String::FlatContent format_content = format->GetFlatContent();
13356 RUNTIME_ASSERT(format_content.IsAscii());
13357 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013358 LOGGER->LogRuntime(chars, elms);
13359 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013360}
13361
13362
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013363RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013364 UNREACHABLE(); // implemented as macro in the parser
13365 return NULL;
13366}
13367
13368
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013369#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13370 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13371 CONVERT_CHECKED(JSObject, obj, args[0]); \
13372 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13373 }
13374
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013375ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013376ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13377ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13378ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13379ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13380ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13381ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13382ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13383ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13384ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13385ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13386ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13387ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13388ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13389
13390#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13391
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013392
13393RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13394 ASSERT(args.length() == 2);
13395 CONVERT_CHECKED(JSObject, obj1, args[0]);
13396 CONVERT_CHECKED(JSObject, obj2, args[1]);
13397 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13398}
13399
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013400// ----------------------------------------------------------------------------
13401// Implementation of Runtime
13402
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013403#define F(name, number_of_args, result_size) \
13404 { Runtime::k##name, Runtime::RUNTIME, #name, \
13405 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013406
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013407
13408#define I(name, number_of_args, result_size) \
13409 { Runtime::kInline##name, Runtime::INLINE, \
13410 "_" #name, NULL, number_of_args, result_size },
13411
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013412static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013413 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013414 INLINE_FUNCTION_LIST(I)
13415 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013416};
13417
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013418
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013419MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13420 Object* dictionary) {
13421 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013422 ASSERT(dictionary != NULL);
13423 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13424 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013425 Object* name_symbol;
13426 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013427 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013428 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13429 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013430 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013431 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13432 String::cast(name_symbol),
13433 Smi::FromInt(i),
13434 PropertyDetails(NONE, NORMAL));
13435 if (!maybe_dictionary->ToObject(&dictionary)) {
13436 // Non-recoverable failure. Calling code must restart heap
13437 // initialization.
13438 return maybe_dictionary;
13439 }
13440 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013441 }
13442 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013443}
13444
13445
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013446const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13447 Heap* heap = name->GetHeap();
13448 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013449 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013450 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013451 int function_index = Smi::cast(smi_index)->value();
13452 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013453 }
13454 return NULL;
13455}
13456
13457
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013458const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013459 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13460}
13461
13462
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013463void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013464 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013465 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013466 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013467 if (isolate->heap()->new_space()->AddFreshPage()) {
13468 return;
13469 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013470 // Try to do a garbage collection; ignore it if it fails. The C
13471 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013472 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013473 } else {
13474 // Handle last resort GC and make sure to allow future allocations
13475 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013476 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013477 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013478 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013479}
13480
13481
13482} } // namespace v8::internal